Only count a download once it's served

删除回忆录丶 提交于 2019-12-03 13:27:15

问题


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.


回答1:


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

Response.Buffer = false;
Response.TransmitFile("Tree.jpg");
Response.Close();
// logging here



回答2:


The write response is an asynchronous process. It is managed by the container for the application. In your case the .NET/ASP.net run time is handling it. If you want to find out when the last chunk was sent you'll have to have some kind of callback/event on that [coming from the container/runtime]. In Java its the application server that gets this information [Glassfish, Tomcat etc]




回答3:


You can try to add this before writing the file:

context.Response.BufferOutput = false;



回答4:


Have you tried handling the EndRequest event of HttpApplication?

Or perhaps, using the ReleaseHandler() method of IHttpHandlerFactory, assuming that you mark your IHttpHandler as non-reusable?




回答5:


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:

  • http://msdn.microsoft.com/en-us/library/12s31dhy.aspx
  • http://msdn.microsoft.com/en-us/library/system.web.httpresponse.binarywrite.aspx
  • http://msdn.microsoft.com/en-us/library/system.web.httpresponse.flush.aspx
  • http://msdn.microsoft.com/en-us/library/system.web.httpresponse.close.aspx
  • http://msdn.microsoft.com/en-us/library/system.web.httpresponse.disablekernelcache.aspx
  • http://msdn.microsoft.com/en-us/library/system.web.httpapplication.endrequest.aspx


来源:https://stackoverflow.com/questions/7534150/only-count-a-download-once-its-served

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!