HttpHandlers and big files

I use an HttpHandler on my podcast site to catch the requests for MP3's and increment a download counter. This seems to work pretty well, and I haven't had any problems to date. It also helps force the "save as" dialog so people aren't viewing them in their browsers.

However, when I try to apply the same concept to big video files, it chokes. iTunes says the network connection is reset while Firefox simply says the document contains no data.

What might be going on here? The code is what you've likely seen in countless examples elsewhere, like this:

public class MovHandler : IHttpHandler
{
    public MovHandler()
    {
    }
   
    public bool IsReusable
    {
        get { return true; }
    }

    public void ProcessRequest(HttpContext context)
    {
        context.Response.Clear();
        context.Response.ContentType = "video/quicktime";
        string path = context.Server.MapPath(context.Request.FilePath);
        NewsItem item = new NewsItem(Path.GetFileName(context.Request.FilePath));
        item.Downloads++;
        item.Update();
        context.Response.WriteFile(path);
        context.Response.End();
    }
}

8 Comments

  • Jeff,

    I believe you need to write the file out manually a chunk of bytes at a time in a loop if the file is greater than 2GB. Make sure you turn response buffering off. Also, you should be using TransmitFile instead of WriteFile since it performs much better.



    Josh

  • How big is the file?



    Another alternative is to use Response.TransmitFile() - it would not read the bits into memory. But it is also limited to 2GB.



    Also, no need to call Response.End.



    Thanks,



    Dmitry

  • By "large," I meant under 100 MB still.

  • I am just wondering how do I know file has been downloaded completely, to maintain a real counter "item.Downloads++;"



    User can click on "cancel" button during the download process, which should not increase a counter value.



  • Well, you don't know, and honestly, I don't care enough to know for sure. :)



    Switching to TransmitFile() solved the problem. That was easy. I'm still curious about the actual implementation of each method, however.

  • I had the same problem, but with memory consumption: WriteFile loads the file completely in memory before streaming it to the client.



    So I switched to TransmitFile to do a test. No memory hogging anymore, but what's weird: the files are sometimes just 64KB, not 11MB. Also, TransmitFile isn't documented in the MSDN. Pretty obscure though...

  • Could this not be better done as a filtering module that simply observed the file fetch and made note of it, rather than a handler that dealt with serving the file? The handler is not actually adding any service value, and so might be redundant... a module should allow you to make the observations you need.

  • Jeff,

    TransmitFile uses a kernel-mode API to stream the file directly onto the network (it's what IIS uses internally) while WriteFile does all sorts of user-mode copying around between buffers before the file ends up on the network.



    Josh

Comments have been disabled for this content.