我创建了一个基于MVC 5的WebAPI控制器 - 为我们的客户提供不同的文件。访问文件的工具也是自编写的 - 基于.NET HttpClient - 但这是另一个故事。
在下载控制器的第一个版本中,我使用了内置机制来提供this等文件
但是那个机制在我的iis文件上崩溃> 4GB。
所以我终于来到了这段代码:
public class DownloadController : ApiController
{
public async Task Get(long id)
{
string fullFilePath = GetFilePathById(id);
string returnFileName = fullFilePath.Split('\\').Last();
FileInfo path = new FileInfo(fullFilePath);
HttpContext.Current.Response.ContentType = "application/zip";
HttpContext.Current.Response.AddHeader("Content-Length", path.Length.ToString());
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + returnFileName);
HttpContext.Current.Response.Flush();
try
{
byte[] buffer = new byte[4096];
using (FileStream fs = path.OpenRead())
{
using (BufferedStream bs = new BufferedStream(fs, 524288))
{
int count = 0;
while ((count = bs.Read(buffer, 0, buffer.Length)) > 0)
{
if (!HttpContext.Current.Response.IsClientConnected)
{
break;
}
HttpContext.Current.Response.OutputStream.Write(buffer, 0, count);
HttpContext.Current.Response.Flush();
}
}
}
}
catch (Exception exception)
{
//Exception logging here
}
}
}
该代码运行良好,我可以通过可接受的CPU使用率和磁盘i / o获得快速下载。但过了一段时间后,我注意到 - 每次下载 - 一个未处理的异常将一个条目写入IIS服务器的应用程序事件日志中,如下所示:
Server cannot set status after HTTP headers have been sent
Exception type: HttpException
Event Log ID 1309
我确定经常使用.Flush()会导致问题,但如果删除其中任何一个,下载就会停止工作。
在类似的问题中,我可以找到Response.BufferOutput = true;
作为解决方案,但这似乎占用了我所有的服务器资源并延迟下载。
任何建议都会很棒!
答案 0 :(得分:1)
问题不在于Flush()
,而在于您未使用HttpContext.Current.Response.Close();
ASP.NET框架并不知道你在action方法中做了什么,所以它通过通常的请求管道传递请求,管道执行所有必要的管道而不是我们。其中之一是它将标头和HTTP状态发送到客户端。但是,当框架尝试执行此操作时,您已经设置并发送了标头。为避免这种情况,您应关闭流,并通过关闭响应流来自行完成处理。