2010-02-18 102 views
1

我的問題與this post類似,但我必須使用IIS,ASP.NET和C#執行相同的操作。如何檢測Web客戶端成功接收文件?

如果數據發送與否,HttpResponse類中的任何方法都不提供反饋,TransmitFile()只是完成其工作(不),並且不提供任何方法來知道結果。

我正在考慮使用.Filter屬性,但再次,該過濾器是基於HttpResponseStream,它也沒有提供任何反饋。

任何想法?

+0

如果發生故障,您不會有任何異常情況嗎? – 2010-02-18 05:02:17

回答

0

在致電TransmitFile後檢查Response.IsClientConnected

+0

不,沒有任何「作家」函數會拋出異常。知道客戶端是否仍在監聽的唯一方法是使用Response.IsClientConnected,如下所述。 – 2010-02-18 12:40:57

1

經過一番測試,我想出了以下解決方案。 TransmitFile()有一個嚴重的限制:它在發送之前將整個文件讀入內存,這對於較大的文件來說確實很糟糕。所以基本上我採取手動分塊和檢查客戶端是否連接每個塊後。

context.Response.Clear(); 
context.Response.BufferOutput = false; 
context.Response.ContentType = "application/octet-stream"; 
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + originalFilename); 
context.Response.AddHeader("Content-Length", fileLength.ToString()); 
context.Response.Cache.SetNoStore(); 

context.Response.Flush(); 

downloadFailed = !context.Response.IsClientConnected; 

int thisChunk; 
long offset = 0; 
int chunkSize = 1024 * 8; 
byte[] bytes = new byte[chunkSize]; 

FileStream r = File.OpenRead(localFilename); 

while((offset < fileLength) && !downloadFailed) 
{ 
    if((fileLength - offset) < chunkSize) 
    { 
     thisChunk = (int)(fileLength - offset); 
    } 
    else 
    { 
     thisChunk = chunkSize; 
    } 

    r.Read(bytes, 0, chunkSize); 

    try 
    { 
     context.Response.BinaryWrite(bytes); 
     context.Response.Flush(); 

     if(!context.Response.IsClientConnected) 
     { 
      downloadFailed = true; 
     } 
    } 
    catch(ObjectDisposedException ex1) 
    { 
     // Stream is closed, nothing written 
     break; 
    } 
    catch(System.IO.IOException ex3) 
    { 
     // I/O error, unknown state, abort 
     Trace.Write(ex3); 
     break; 
    } 

    offset += thisChunk; 
} 

if(!downloadFailed) 
{ 
    // now update the file, statistics, etc 
} 

context.Response.Flush(); 

HttpContext.Current.ApplicationInstance.CompleteRequest(); 

需要用塊大小玩一下才能找到最佳大小。但基本上它可以像這樣可靠地工作。