Alex Rivera | Logout

Only count a download once it's served

Asked 2011-09-23T19:57:21.880
10

We have this code which serves a download:

public class downloadRelease : IHttpHandler {

    public void ProcessRequest (HttpContext context) {

        -- snip --

        context.Response.Clear();
        context.Response.ContentType = "application/octet-stream";
        context.Response.AddHeader("Content-Disposition", "attachment; filename=" + OriginalFileName);
        context.Response.WriteFile(Settings.ReleaseFileLocation + ActualFileName);

        // Log download
        Constructor.VersionReleaseDownload.NewReleaseDownload(ActualFileName);

It works fine, except that the log download code runs as soon as the download starts seemingly, not when the download has fully completed as we expect.

Can someone explain why this is, and how to change it so it only logs when it's completed? We don't want to count partial downloads.

Edit
Report

2 Answers

5

This blog post has exactly same issue as yours and a solution too.

Response.Buffer = false;
Response.TransmitFile("Tree.jpg");
Response.Close();
// logging here
answered 2011-09-26T08:14:44.023
1

This is a bit tricky... depending on how precise you want the logging to be it might even be that it is not possible... but there are the following options with the Response object :

  • BinaryWrite / Flush / Close

  • TransmitFile / Flush / Close

The first option requires you to read the file chunk after chunk calling BinaryWrite and Flush for every chunk...

The second option is easier to implement since it is just a call to TransmitFile and then to Flush.

After everything is sent and before logging you need to call Close.

In any case it can help to call DisableKernelCache before starting to send a response...

BEWARE that all of the above will show a noticeable performance hit! This effect can be reduced by creating an in-memory-cache for the files you want to serve though...

As to the logging I would consider moving the logging code to the EndRequest event handler...

AFAIK this is the nearest you can get to your goal except writing your own TcpListener-based HTTP server or hacking IIS / HTTP.SYS .

Some reference links:

Your Answer