2012-11-29 25 views
4

我很難完成某件事。將文件異步下載到客戶端

我建立使用asp.net MVC 4

我在,我要下載相關的信息(而不是附件)到客戶端瀏覽器中的圖像點的的MailClient。

現在我有這種設置:

客戶端瀏覽器 - >控制器/後端 - >郵件服務器

澄清:我有包含圖像的內容ID的客戶機請求,右郵箱,消息等等。有了這些信息,我可以從郵件服務器下載圖像並將其上傳到客戶端。 現在到了困難的部分:我想要做到這一點異步。我希望能夠從郵件服務器下載512 KB的大塊文件,解碼該部分,並將其發送到客戶端。fetch - decode - send ..只要瀏覽器獲取了圖像的所有數據。

我只是不想先將所有數據先下載到服務器,然後創建一個包含所有數據的新內存流,並將其作爲文件結果返回。我太害怕在我的內存中獲取太大的文件,並阻止其他進程等。

我打算使用這種方法也上傳真實附件(可能是100 MB的MB)。所以我以後會需要這種方法。

現在我只是不知道如何實現這一點,因爲我有一個連接到郵件服務器,我有一個連接到客戶端。我必須通過數據到一個新的流或東西才能完成這個..

有人可以幫我嗎?

編輯:澄清:不,我不能指郵件服務器上的文件。我必須通過套接字將文件下載到服務器。

Edit2:可以http chuncked是解決方案嗎?如果是的話,你能給我一個小例子嗎?

+0

您需要支持哪種客戶端瀏覽器?他們是否支持websockets?就本質而言,您只希望您的郵件服務器代理一個流,據我所知,這將取決於您的瀏覽器支持要求。 – Gijs

+0

我無法支持任何websocket(需要與IE 8,IE 9兼容)。我能以某種方式傳遞一個流並告訴控制器/響應從中讀取X個字符嗎?因爲這樣可以解決所有問題 –

+0

無論是或者只是讓你的服務器作爲一個反向代理(所以當客戶端請求一個URL時,一次性傳回數據,而不需要手動分塊或使用套接字)。不幸的是,我對ASP.NET的瞭解不夠,無法對此有所幫助。 – Gijs

回答

4

你只需要將數據從一個流(tcp連接到郵件服務器)複製到另一個(http連接到瀏覽器),對吧?如果您想擴展,您需要使用非阻塞IO,如this article中所述。所以你需要從IHttpAsyncHandler實現中調用那篇文章中的代碼。你會像這樣結束:

class MyHandler : IHttpAsyncHandler 
{ 
    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) 
    { 
     Stream src = null; // remote data source 
     Stream dst = context.Response.OutputStream; 

     // set content type, etc 

     var res = new MyResult(); 

     AsynchCopy(src, dst,() => 
      { 
       ((ManualResetEvent)res.AsyncWaitHandle).Set(); 
       cb(res); 
       src.Close(); 
       dst.Flush(); 
      }); 

     return res; 
    } 

    public void EndProcessRequest(IAsyncResult result) 
    { 
    } 

    public bool IsReusable 
    { 
     get { return true; } 
    } 

    public void ProcessRequest(HttpContext context) 
    { 
     throw new NotImplementedException(); 
    } 

    class MyResult : IAsyncResult 
    { 
     public MyResult() 
     { 
      AsyncWaitHandle = new ManualResetEvent(false); 
     } 

     public object AsyncState 
     { 
      get { return null; } 
     } 

     public WaitHandle AsyncWaitHandle 
     { 
      get; 
      private set; 
     } 

     public bool CompletedSynchronously 
     { 
      get { return false; } 
     } 

     public bool IsCompleted 
     { 
      get { return AsyncWaitHandle.WaitOne(0); } 
     } 
    } 

    public static void AsynchCopy(Stream src, Stream dst, Action done) 
    { 
     byte[] buffer = new byte[2560]; 
     AsyncCallback readCallback = null, writeCallback = null; 

     readCallback = (readResult) => 
     { 
      int read = src.EndRead(readResult); 
      if (read > 0) 
      { 
       dst.BeginWrite(buffer, 0, read, writeCallback, null); 
      } 
      else 
      { 
       done(); 
      } 
     }; 

     writeCallback = (writeResult) => 
     { 
      dst.EndWrite(writeResult); 
      src.BeginRead(buffer, 0, buffer.Length, readCallback, null); 
     }; 

     src.BeginRead(buffer, 0, buffer.Length, readCallback, null); 
    } 
} 

上面的代碼是未經測試,並且不包含錯誤處理,但它應該讓你開始。

+0

感謝您的想法和您的示例代碼!只要我能夠達到目的,我會試一試! 我認爲在我們的架構中很難實現,但異步部分會救我,我想。我會盡快回復它! –