MVC 5 WebAPI - 下载文件 - HttpException

M. *_*ann 6 c# asp.net-web-api

我创建了一个基于MVC 5的WebAPI控制器 - 为我们的客户提供不同的文件.访问文件的工具也是自编写的 - 基于.NET HttpClient - 但这是另一个故事.

在下载控制器的第一个版本,我使用的生成机制来提供像文件这样

但是这个机制在我的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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

该代码运行良好,我可以通过可接受的CPU使用率和磁盘i/o获得快速下载.但过了一段时间后,我注意到 - 每次下载 - 一个未处理的异常将一个条目写入IIS服务器的Application Eventlog,如下所示:

Server cannot set status after HTTP headers have been sent

Exception type: HttpException

Event Log ID 1309
Run Code Online (Sandbox Code Playgroud)

我确信反复使用.Flush()会导致问题,但是如果我删除其中任何一个,下载就会停止工作.

在类似的问题中,我可以找到Response.BufferOutput = true;解决方案,但这似乎占用了我所有的服务器资源并延迟了下载.

任何建议都会很棒!

Tam*_*mas 1

问题不在于Flush(),而是您没有自己关闭响应流HttpContext.Current.Response.Close();

ASP.NET 框架不知道您在操作方法内做什么,因此它通过通常的请求管道传递请求,该管道代替我们完成所有必要的管道工作。其中之一是将标头和 HTTP 状态发送到客户端。但是,当框架尝试这样做时,您已经设置并发送了标头。为了避免这种情况,您应该关闭流,并通过关闭响应流来完成处理。