Только считайте загрузку после ее подачи

У нас есть этот код, который служит для загрузки:

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);

Он отлично работает, за исключением того, что код загрузки журнала запускается, как только начинается загрузка, а не когда загрузка полностью завершена, как мы ожидаем.

Может кто-нибудь объяснить, почему это так, и как изменить его, чтобы он регистрировался только после его завершения? Мы не хотим считать частичную загрузку.

Ответ 1

Это сообщение в блоге имеет точно такую ​​же проблему, как и ваша, и решение тоже.

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

Ответ 2

Ответ на запись - это асинхронный процесс. Он управляется контейнером для приложения. В вашем случае время выполнения .NET/ASP.net обрабатывает его. Если вы хотите узнать, когда был отправлен последний кусок, вам придется иметь какой-то callback/event на этом [из контейнера/времени выполнения]. В Java его сервер приложений, который получает эту информацию [Glassfish, Tomcat и т.д.]

Ответ 3

Вы можете попробовать добавить это перед записью файла:

context.Response.BufferOutput = false;

Ответ 4

Это немного сложно... в зависимости от того, насколько точным вы хотите, чтобы журнал был, возможно, даже в том, что это невозможно... но есть следующие опции с объектом Response:

  • BinaryWrite/Flush/Close

  • TransmitFile/Flush/Close

Первый параметр требует, чтобы вы прочитали фрагмент файла после фрагмента, вызывающего BinaryWrite и Flush для каждого фрагмента...

Второй вариант проще реализовать, поскольку это просто вызов TransmitFile, а затем Flush.

После того, как все отправлено и перед протоколированием вам нужно позвонить Close.

В любом случае он может помочь вызвать DisableKernelCache, прежде чем приступать к отправке ответа...

BEWARE, что все вышеперечисленное покажет заметное поражение производительности! Этот эффект может быть уменьшен путем создания кэша в памяти для файлов, которые вы хотите обслуживать, хотя...

Что касается журнала, я бы рассмотрел возможность переноса кода регистрации в обработчик события EndRequest...

AFAIK, это ближайшая к вам цель, за исключением написания собственного HTTP-сервера на основе TcpListener или взлома IIS/HTTP.SYS.

Некоторые ссылочные ссылки:

Ответ 5

Вы пытались обработать событие EndRequest для HttpApplication?

Или, возможно, используя метод ReleaseHandler() для IHttpHandlerFactory, предполагая, что вы отмечаете свой IHttpHandler как неприменимый?