MVC 5 WebAPI - 下载文件 - HttpException

时间:2016-02-11 14:20:15

标签: c# asp.net-web-api

我创建了一个基于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;作为解决方案,但这似乎占用了我所有的服务器资源并延迟下载。

任何建议都会很棒!

1 个答案:

答案 0 :(得分:1)

问题不在于Flush(),而在于您未使用HttpContext.Current.Response.Close();

自行关闭响应流

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