Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC 5 WebAPI - Download Files - HttpException

I've created a WebAPI Controller - based on MVC 5 - that provides different files for our customers. The tool to access the files is also self written - based on .NET HttpClient - but thats an other story.

In the first version of the download controller I've used the build in mechanism to provide the files like this

But that mechanism crashed on my iis for files > 4GB.

So I finally came to this code:

    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
        }
    }
}

That code works very well and I got fast downloads with acceptable CPU usage and disk i/o. But after some time I noticed that - with every single download - an unhandled exception writes an entry into the Application Eventlog of the IIS server like this:

Server cannot set status after HTTP headers have been sent

Exception type: HttpException

Event Log ID 1309

I'm sure that the recurring use of .Flush() causes the problem, but if I remove any of these the download stops working.

In similar questions I can find Response.BufferOutput = true; as a solution but that seems to eat all my server resources and delays the download.

Any suggestions would be great!

like image 708
M. Altmann Avatar asked Feb 11 '16 14:02

M. Altmann


Video Answer


1 Answers

The problem is not with the Flush(), but that you are not closing the response stream yourself with HttpContext.Current.Response.Close();

The ASP.NET framework doesn't know what you are doing inside the action method, so it passes the request through the usual request pipe, which does all the necessary plumbing instead of us. One of this is that it sends the headers and HTTP status to the client. However you have already set and sent the headers when the framework tries to do that. To avoid this you should close the stream, and finish the processing yourself by closing the response stream.

like image 54
Tamas Avatar answered Oct 03 '22 08:10

Tamas