Подтвердить что ты не робот

Использование Handler для отслеживания файлов

В настоящее время я работаю над сайтом, который разрабатывается с использованием Asp.Net и С#. Я использую Asp.Net Handler, чтобы пользователи могли загружать файлы. Я могу скачать файлы без проблем. Однако мне нужно регистрировать, какие файлы были загружены успешно. Кажется, эта часть работает неправильно. Например. если я нажму на файл для загрузки, а затем нажмите "Отмена" в подсказке браузера, мой код все еще записывается в журнал. Я не могу понять, как я могу записать в журнал только, когда файл успешно загружен.

Мой код ниже.

public void ProcessRequest(HttpContext context)
{
    string logFilePath = "PathToMyLogFile";
    string filePath = Uri.UnescapeDataString(context.Request.QueryString["file"]);
    string fileName = Path.GetFileName(filePath);

    if (context.Response.IsClientConnected) //Shouldn't this tell me if the client is connected or not?
    {
        using (var writer = new StreamWriter(logFilePath, true))
        {
            if (!File.Exists(logFilePath))
            {
                //Create log file if one does not exist
                File.Create(logFilePath);
            }
            else
            {
                writer.WriteLine("The following file was downloaded \"{0}\" on {1}", fileName, DateTime.Now.ToString("dd/MM/yyyy") + " at " + DateTime.Now.ToString("HH:mm:ss"));
                writer.WriteLine(Environment.NewLine + "-----------------------------------------------------------------------------" + Environment.NewLine);
            }
        }
    }

    context.Response.ContentType = "application/octet-stream";
    context.Response.AppendHeader("Content-Disposition", "attachment;filename=\"" + Path.GetFileName(filePath));
    context.Response.WriteFile(filePath);
    context.Response.End();
}

Я ценю вашу помощь и поддержку.

4b9b3361

Ответ 1

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

Важной частью является "context.Response.IsClientConnected" во время/после отправки данных.

В этом примере будет отправляться бесконечный файл со случайными данными. Вы можете протестировать его во всех браузерах, как именно они будут себя вести. Я тестировал его только в Chrome.

/// <summary>
/// Writes random data.
/// </summary>
public class NeverendingFile : IHttpHandler {
    public bool IsReusable {
        get { return false; }
    }

    public void ProcessRequest(HttpContext context) {
        context.Response.Buffer = false;
        context.Response.BufferOutput = false;
        context.Response.ContentType = "application/octet-stream";
        context.Response.AppendHeader("Content-Disposition", "attachment;filename=\"Neverendingfile.dat\"");
        context.Response.Flush();

        // flag used for debuging, in production it will be always false => writing into output stream will nevere ends
        var shouldStop = false;
        for(var i = 0; !shouldStop; i++) {
            // chunk contains random data
            var chunk = Guid.NewGuid().ToByteArray();

            for (var a = 0; a < 1000; a++) {
                context.Response.OutputStream.Write(chunk, 0, chunk.Length);
            }
            context.Response.OutputStream.Flush();
            // sleep is just for slowing the download
            System.Threading.Thread.Sleep(10);

            if (!context.Response.IsClientConnected) {
                // the download was canceled or broken
                return;
            }
        }
    }
}

EDIT: Отредактированный исходный код:

public void ProcessRequest(HttpContext context) {
    string logFilePath = "PathToLogFile";
    //Determine the file path
    string filePath = Uri.UnescapeDataString(context.Request.QueryString["file"]);
    //Determine the file name
    string fileName = Path.GetFileName(filePath);

    context.Response.Buffer = false;
    context.Response.BufferOutput = false;
    context.Response.ContentType = "application/octet-stream";
    context.Response.AppendHeader("Content-Disposition", "attachment;filename=\"" + Path.GetFileName(filePath));
    context.Response.WriteFile(filePath);
    context.Response.Flush();
    context.Response.OutputStream.Flush();

    if (!context.Response.IsClientConnected) {
        // the download was canceled or broken
        using (var writer = new StreamWriter(logFilePath, true)) {
            if (!File.Exists(logFilePath)) {
                //Create log file if one does not exist
                File.Create(logFilePath);
            }
            else {
                writer.WriteLine("The Download was canceled");
            }
        }
        return;
    }

    context.Response.End();
}

Ответ 2

Я предполагаю, что кнопки загрузки и отмены находятся на одной странице. Я создал следующий пример, чтобы проверить, загружен ли файл при отмене использования одного класса, который имеет флаг "isFileDownload" , чтобы значение флага не было инициализировано для каждого запроса для того же пользователя.

  • Каждый раз, когда запрос поступает от пользователя, назначьте "isFileDownload" json переменная в "isFileDownload" для одноэлементного класса.
  • Когда запрос на загрузку файла приходит к обработчику, "isFileDownload" singleton будет установлен в true. при отправке ответа пользователю, проверьте, действительно ли "isFileDownload" true den log else dont.
  • если пользователь нажимает кнопку загрузки, тогда "isFileDownload" = true, и пользователь нажимает кнопку отмены до того, как файл будет загружен, тогда "isFileDownload" = false.
  • Так как свойство isFileDownload является частью класса singleton, тот же экземпляр будет обновлен.

FYI, Я новичок в обработчиках. Заранее спросите, если я пропустил что-то, чтобы принять во внимание при публикации этого

Класс обработчика:

public class DownloadFile : IHttpHandler
{

    public void ProcessRequest(HttpContext context)
    {
        string fileName = @"test.txt";
        string filePath = context.Server.MapPath("/test.txt");
        string logFilePath = context.Server.MapPath("/Log.txt");
        //string filePath = Uri.UnescapeDataString(context.Request.QueryString["file"]);
        //string fileName = Path.GetFileName(filePath);
        Singleton s = Singleton.Instance;
        s.isFileDownload = Convert.ToBoolean(context.Request.Form["isFileDownload"]);
        if (context.Response.IsClientConnected) //Shouldn't this tell me if the client is connected or not?
        {

            using (var writer = new StreamWriter(logFilePath,true))
            {
                if (!File.Exists(logFilePath))
                {
                    //Create log file if one does not exist
                    File.Create(logFilePath);
                }
                else
                {
                    writer.WriteLine("The following file was downloaded \"{0}\" on {1}", fileName, DateTime.Now.ToString("dd/MM/yyyy") + " at " + DateTime.Now.ToString("HH:mm:ss"));
                    writer.WriteLine(Environment.NewLine + "-----------------------------------------------------------------------------" + Environment.NewLine);
                }
            }
        }

        //To mock the large file download
        if (s.isFileDownload)
        System.Threading.Thread.Sleep(10000);

        if (context.Response.IsClientConnected )
        {
            if (s.isFileDownload){
            System.Threading.Thread.Sleep(100);
            context.Response.ContentType = "application/octet-stream";
            context.Response.AppendHeader("Content-Disposition", "attachment;filename=\"" + Path.GetFileName(filePath));
            context.Response.WriteFile(filePath);
            context.Response.OutputStream.Flush();
            context.Response.End();
        }
            else
            {
                return;
            }
        }
        else
        {
            return;
        }


    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}

Класс Singleton: Ссылка

public sealed class Singleton
{
    private static volatile Singleton instance;
    private static object syncRoot = new Object();

    private Singleton() { }

    public static Singleton Instance
    {
        get
        {
            if (instance == null)
            {
                lock (syncRoot)
                {
                    if (instance == null)
                        instance = new Singleton();
                }
            }

            return instance;
        }
    }

    public bool isFileDownload { get; set; }
}

Html Страница:

$(document).ready(function(){ 
var isFileDownload = false;
        $("#download").click(function () {
            isFileDownload = true;
            console.log(isFileDownload);
            $.ajax({
                method: "POST",
                url: "DownloadFile.ashx",
                data: { isFileDownload:true }
            }).done(function (data) {
                alert(data);
               
            });
        });

        $("#cancel").click(function () {
            if (isFileDownload) {
                $.ajax({
                    method: "POST",
                    url: "DownloadFile.ashx",
                    data: { isFileDownload: false }
                }).done(function (data) {
                    alert("canceld");
                    isFileDownload = false;
                });
            }
        });
        $(document).ajaxComplete(function () {
            isFileDownload = false;
        });
)};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<button type="button" value="DownLoad" id="download" title="Download">Download</button>
<button type="button" value="Cancel" id="cancel" title="Cancel">Cancel</button>
  </body>

Ответ 3

Когда появляется всплывающее окно браузера, это означает, что сервер начал отправлять (передавать) данные клиенту. В действительности вы не можете определить, была ли загрузка файла успешной или нет. Вы можете только определить, сколько байтов было отправлено клиенту, и если количество байтов равно длине файла, вы можете предположить, что клиент смог загрузить файл, но вы не можете получить доказательство того, что файл был успешно сохранен на клиентская машина/среда.

Пример: если я загружаюсь под Linux и пересылаю поток в /dev/null, вы увидите, что я загрузил этот файл, но на самом деле файл не будет существовать на моей машине.