只有在下载完成后才计算下载次数

10
我们有这段代码用于提供下载:
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);

它能正常工作,除了日志下载代码似乎会在下载开始时立即运行,而不是当我们期望的下载完全完成后再运行。

有人能解释一下为什么会这样,并且如何更改它以便只在完成时记录日志吗? 我们不想计算部分下载。

5个回答

5
这篇博客文章与你们遇到的问题完全相同,它也提供了解决方案。
Response.Buffer = false;
Response.TransmitFile("Tree.jpg");
Response.Close();
// logging here

太棒了,谢谢!运行得很好。不过它没有发送文件大小,所以下载时间未知,但我认为我可以解决这个问题。 - Tom Gullen
1
感谢您的代码,它非常好用!请将以下内容翻译成中文:context.Response.AddHeader("Content-Length", FileSize.ToString()); - Tom Gullen
@TomGullen 我没有得到它的赏金。 - Muhammad Hasan Khan
不用担心,我正在尝试,但它说我必须等待,现在还为时过早。 - Tom Gullen

4
写入响应是一个异步的过程。它由应用程序容器管理。在您的例子中,.NET/ASP.net运行时正在处理它。如果您想知道最后一块何时发送,您将必须在其中有某种回调/事件[来自容器/运行时]。在Java中,它是应用服务器获取这些信息的[如Glassfish、Tomcat等]。

1

在写入文件之前,您可以尝试添加以下内容:

context.Response.BufferOutput = false;

1

这有点棘手...取决于您想要多精确的日志记录,甚至可能不可能...但是在Response 对象中有以下选项:

  • BinaryWrite / Flush / Close

  • TransmitFile / Flush / Close

第一个选项需要你逐块读取文件并为每个块调用BinaryWriteFlush...

第二个选项更容易实现,因为只需调用TransmitFile,然后再调用Flush.

在发送了所有内容之后,在记录日志之前,需要调用Close

无论哪种情况,开始发送响应之前调用DisableKernelCache可能会有所帮助...

注意以上所有操作都会导致明显的性能下降!但是可以通过为要提供的文件创建内存缓存来减少此影响...

关于日志记录,我建议将记录代码移至EndRequest事件处理程序中...

据我所知,除非编写自己的基于TcpListener的HTTP服务器或黑客IIS/HTTP.SYS,否则这是您可以实现目标的最佳方法。

一些参考链接:


1
你尝试过处理 HttpApplication 的 EndRequest 事件吗?
或者可以使用 IHttpHandlerFactory 的 ReleaseHandler() 方法,假设你标记了你的 IHttpHandler 为不可重用的?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接