使用Handler跟踪文件

时间:2015-09-30 14:21:39

标签: c# asp.net

我目前正在开发一个使用Asp.Net和C#开发的网站。我正在使用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();
}

感谢您的所有帮助和支持。

3 个答案:

答案 0 :(得分:4)

我尝试创建一个简单的处理程序,它可以检测从服务器端角度取消/中断下载。

在发送数据期间/之后,重要的部分是“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;
            }
        }
    }
}

修改 编辑过的源代码:

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

答案 1 :(得分:1)

我假设下载和取消按钮都在同一页面上。 我创建了以下示例来检查文件是否已经开始下载,同时取消使用具有标记的单例类&#34; isFileDownload&#34;这样就不会为同一用户的每个请求初始化标志值。

  1. 每次请求来自用户时,请指定&#34; isFileDownload&#34; JSON 变量到&#34; isFileDownload&#34;单身阶级。
  2. 当文件下载请求进入处理程序时,&#34; isFileDownload&#34;单身人士将被设为真。在将响应发送回用户的同时,检查&#34; isFileDownload&#34;真正的登录否则不要。
  3. 如果用户点击下载按钮,那么&#34; isFileDownload&#34; = true并且用户在下载文件之前单击取消按钮然后&#34; isFileDownload&#34; = false。
  4. 因为&#34; isFileDownload&#34; property是singleton类的一部分,同一个实例将被更新。
  5. 仅供参考,我是处理人员的新手。如果我在发布此内容时遗漏了一些内容,请提前预订

    处理程序类:

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

    单身人士课程: Reference

    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页面:

    &#13;
    &#13;
    $(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;
            });
    )};
    &#13;
    <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>
    &#13;
    &#13;
    &#13;

答案 2 :(得分:0)

当出现浏览器弹出窗口时,表示服务器已开始将数据发送(流)到客户端。实际上无法检测文件下载是否成功。 您只能检测发送到客户端的字节数,如果字节数等于文件长度,您可以假设客户端能够下载文件,但您无法获得证明该文件已成功保存在客户端的计算机/环境中。

示例:如果我在linux下载并将流转发到/ dev / null,您将看到我已经下载了该文件,但实际上该文件将不存在于我的机器上。