今天的問題是,當使用WebApi 2和基於異步ApiController的Get方法時,它返回文件的內容。當我將Get方法更改爲同步時,它工作得很好,但只要我將其轉換回異步,它就會過早關閉流。 (提琴手報告連接已中止)工作同步代碼:C#異步ApiController過早關閉OutputStream
public void Get(int id)
{
try
{
FileInfo fileInfo = logic.GetFileInfoSync(id);
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.ClearContent();
response.Buffer = true;
response.AddHeader("Content-Disposition", "attachment; filename=\"" + fileInfo.Node.Name + fileInfo.Ext + "\"");
response.AddHeader("Content-Length", fileInfo.SizeInBytes.ToString());
response.ContentType = "application/octet-stream";
logic.GetDownloadStreamSync(id, response.OutputStream);
response.StatusCode = (int)HttpStatusCode.OK;
//HttpContext.Current.ApplicationInstance.CompleteRequest();
response.End();
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
而且GetDownloadStreamSync如下:
public async Task GetDownloadStream(string fileIdentifier, Stream streamToCopyTo)
{
string filePath = Path.Combine(fileIdentifierFolder, fileIdentifier);
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None, BufferSize, false))
{
fs.CopyTo(streamToCopyTo);
}
}
--------異步代碼----- -----
的異步版本是完全一樣的,除了:
public async Task Get(int id)
{
FileInfo fileInfo = await logic.GetFileInfoSync(id); // database opp
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.ClearContent();
response.Buffer = true;
response.AddHeader("Content-Disposition", "attachment; filename=\"" + fileInfo.Node.Name + fileInfo.Ext + "\"");
response.AddHeader("Content-Length", fileInfo.SizeInBytes.ToString());
response.ContentType = "application/octet-stream";
await logic.GetDownloadStreamSync(id, response.OutputStream);
//database opp + file I/O
response.StatusCode = (int)HttpStatusCode.OK;
//HttpContext.Current.ApplicationInstance.CompleteRequest();
response.End();
}
隨着異步執行GetDo的wnloadStream如下:(streamToCopyTo從response.OutputStream OutputStream的)
public async Task GetDownloadStream(string fileIdentifier, Stream streamToCopyTo)
{
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None, BufferSize, true))
{
await fs.CopyToAsync(streamToCopyTo);
}
}
我們正試圖從正面擁抱異步/ AWAIT模式回來,所以希望有人意識到爲什麼會失敗?我也嘗試不調用Response.End(),Response.Flush()和HttpContext.Current.ApplicationInstance.CompleteRequest()。另外,爲了迴應下面的問題/評論,我在響應中放置了一個斷點.End()的結果是它沒有被GetDownloadStream方法命中。也許OutputStream不是異步的?任何想法都歡迎! 謝謝
**************************最終解決方案**************** ***********
非常感謝大家的評論,尤其是對@Noseratio對FileOptions.DeleteOnClose的建議。
[HttpGet]
public async Task<HttpResponseMessage> Get(long id)
{
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
Node node = await logic.GetFileInfoForNodeAsync(id);
result.Content = new StreamContent(await logic.GetDownloadStreamAsync(id));
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = node.Name + node.FileInfo.Extension
};
result.Content.Headers.ContentLength = node.FileInfo.SizeInBytes;
return result
}
隨着GetDownloadStreamAsync看起來像這樣:
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None, BufferSize, FileOptions.DeleteOnClose | FileOptions.Asynchronous);
我離開了,我也被解密上飛文件流,這不工作,所以對於那些有興趣...
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None, BufferSize, FileOptions.DeleteOnClose | FileOptions.Asynchronous);
RijndaelManaged rm = new RijndaelManaged();
return new CryptoStream(fs, GetDecryptor(rm, password), CryptoStreamMode.Read);
這裏是MSDN的解釋是:「一個等待表達式不會阻止它在其上執行線程相反,它會導致編譯器將異步方法的其餘部分註冊爲待處理任務的延續,然後控制權返回給異步方法的調用者,當任務完成時,它調用其繼續,並且異步方法的執行從其停止的地方恢復。 只有在直接使用封閉方法,lambda表達式或由異步修飾符標記的匿名方法的主體中才會出現等待表達式。在其他地方,它將被解釋爲標識符。「 – user1789573 2015-02-10 18:44:22
什麼是異步中方法的簽名案件? (我假設「Task Get ...」,但最好確定)。 – 2015-02-10 18:56:30
如果您錯過了您的問題中的某些內容,您可以發佈完整的異步版本嗎? – EZI 2015-02-10 18:57:29