文件上传进度

发布于 2024-08-29 20:10:58 字数 3030 浏览 5 评论 0原文

我一直在尝试跟踪文件上传的进度,但始终陷入死胡同(从 C# 应用程序而不是网页上传)。

我尝试使用 WebClient 如下:

class Program
{
    static volatile bool busy = true;

    static void Main(string[] args)
    {
        WebClient client = new WebClient();
        // Add some custom header information

        client.Credentials = new NetworkCredential("username", "password");
        client.UploadProgressChanged += client_UploadProgressChanged;
        client.UploadFileCompleted += client_UploadFileCompleted;

        client.UploadFileAsync(new Uri("http://uploaduri/"), "filename");

        while (busy)
        {
            Thread.Sleep(100);
        }
        Console.WriteLine("Done: press enter to exit");
        Console.ReadLine();
    }

    static void client_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
    {
        busy = false;
    }

    static void client_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
    {
        Console.WriteLine("Completed {0} of {1} bytes", e.BytesSent, e.TotalBytesToSend);
    }
}

文件确实上传并打印了进度,但进度比实际上传快得多,并且上传大文件时进度将在几秒钟内达到最大值但实际上传需要几分钟(不仅仅是等待响应,所有数据还没有到达服务器)。

因此,我尝试使用 HttpWebRequest 来传输数据(我知道这并不完全等同于文件上传,因为它不会生成 multipart/form-data 内容,但它确实可以说明我的问题)。我设置了AllowWriteStreamBuffering = false并按照此问题/答案

class Program
{
    static void Main(string[] args)
    {
        FileInfo fileInfo = new FileInfo(args[0]);
        HttpWebRequest client = (HttpWebRequest)WebRequest.Create(new Uri("http://uploadUri/"));
        // Add some custom header info
        client.Credentials = new NetworkCredential("username", "password");

        client.AllowWriteStreamBuffering = false;
        client.ContentLength = fileInfo.Length;
        client.Method = "POST";

        long fileSize = fileInfo.Length;
        using (FileStream stream = fileInfo.OpenRead())
        {
            using (Stream uploadStream = client.GetRequestStream())
            {
                long totalWritten = 0;
                byte[] buffer = new byte[3000];
                int bytesRead = 0;
                while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    uploadStream.Write(buffer, 0, bytesRead);
                    uploadStream.Flush();
                    Console.WriteLine("{0} of {1} written", totalWritten += bytesRead, fileSize);
                }
            }
        }
        Console.WriteLine("Done: press enter to exit");
        Console.ReadLine();
    }
}

直到整个文件已写入流并且在启动时已显示完整进度后,请求才会启动(我使用 fiddler 来验证这一点)。我还尝试将 SendChunked 设置为 true(也设置和不设置 ContentLength)。看起来数据在通过网络发送之前仍然被缓存。

这些方法之一是否有问题,或者是否有另一种方法可以跟踪 Windows 应用程序文件上传的进度?

I've been trying to track the progress of a file upload but keep on ending up at dead ends (uploading from a C# application not a webpage).

I tried using the WebClient as such:

class Program
{
    static volatile bool busy = true;

    static void Main(string[] args)
    {
        WebClient client = new WebClient();
        // Add some custom header information

        client.Credentials = new NetworkCredential("username", "password");
        client.UploadProgressChanged += client_UploadProgressChanged;
        client.UploadFileCompleted += client_UploadFileCompleted;

        client.UploadFileAsync(new Uri("http://uploaduri/"), "filename");

        while (busy)
        {
            Thread.Sleep(100);
        }
        Console.WriteLine("Done: press enter to exit");
        Console.ReadLine();
    }

    static void client_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
    {
        busy = false;
    }

    static void client_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
    {
        Console.WriteLine("Completed {0} of {1} bytes", e.BytesSent, e.TotalBytesToSend);
    }
}

The file does upload and progress is printed out but the progress is much faster than the actual upload and when uploading a large file the progress will reach the maximum within a few seconds but the actual upload takes a few minutes (it is not just waiting on a response, all the data have not yet arrived at the server).

So I tried using HttpWebRequest to stream the data instead (I know this is not the exact equivalent of a file upload as it does not produce multipart/form-data content but it does serve to illustrate my problem). I set AllowWriteStreamBuffering = false and set the ContentLength as suggested by this question/answer:

class Program
{
    static void Main(string[] args)
    {
        FileInfo fileInfo = new FileInfo(args[0]);
        HttpWebRequest client = (HttpWebRequest)WebRequest.Create(new Uri("http://uploadUri/"));
        // Add some custom header info
        client.Credentials = new NetworkCredential("username", "password");

        client.AllowWriteStreamBuffering = false;
        client.ContentLength = fileInfo.Length;
        client.Method = "POST";

        long fileSize = fileInfo.Length;
        using (FileStream stream = fileInfo.OpenRead())
        {
            using (Stream uploadStream = client.GetRequestStream())
            {
                long totalWritten = 0;
                byte[] buffer = new byte[3000];
                int bytesRead = 0;
                while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    uploadStream.Write(buffer, 0, bytesRead);
                    uploadStream.Flush();
                    Console.WriteLine("{0} of {1} written", totalWritten += bytesRead, fileSize);
                }
            }
        }
        Console.WriteLine("Done: press enter to exit");
        Console.ReadLine();
    }
}

The request does not start until the entire file have been written to the stream and already shows full progress at the time it starts (I'm using fiddler to verify this). I also tried setting SendChunked to true (with and without setting the ContentLength as well). It seems like the data still gets cached before being sent over the network.

Is there something wrong with one of these approaches or is there perhaps another way I can track the progress of file uploads from a windows application?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

更新:

这个控制台应用程序按预期为我工作:

static ManualResetEvent done = new ManualResetEvent(false);
    static void Main(string[] args)
    {
        WebClient client = new WebClient();
        client.UploadProgressChanged += new UploadProgressChangedEventHandler(client_UploadProgressChanged);
        client.UploadFileCompleted += new UploadFileCompletedEventHandler(client_UploadFileCompleted);
        client.UploadFileAsync(new Uri("http://localhost/upload"), "C:\\test.zip");

        done.WaitOne();

        Console.WriteLine("Done");
    }

    static void client_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
    {
        done.Set();
    }

    static void client_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
    {
        Console.Write("\rUploading: {0}%  {1} of {2}", e.ProgressPercentage, e.BytesSent, e.TotalBytesToSend);
    }

Updated:

This console app works for me as expected:

static ManualResetEvent done = new ManualResetEvent(false);
    static void Main(string[] args)
    {
        WebClient client = new WebClient();
        client.UploadProgressChanged += new UploadProgressChangedEventHandler(client_UploadProgressChanged);
        client.UploadFileCompleted += new UploadFileCompletedEventHandler(client_UploadFileCompleted);
        client.UploadFileAsync(new Uri("http://localhost/upload"), "C:\\test.zip");

        done.WaitOne();

        Console.WriteLine("Done");
    }

    static void client_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
    {
        done.Set();
    }

    static void client_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
    {
        Console.Write("\rUploading: {0}%  {1} of {2}", e.ProgressPercentage, e.BytesSent, e.TotalBytesToSend);
    }
握住我的手 2024-09-05 20:10:59

我相信您的请求正在通过网络进行传输。我发现 Fiddler 2.3.4.4 不显示部分请求,但 MS网络监视器可以显示各个数据包,但不能显示本地主机环回(因此如果您想验证,服务器和客户端需要位于不同的计算机上)。

我在此处遇到了相同的隐藏缓冲问题,并相信其中之一服务器上未正确设置用于流式传输的 WCF 服务设置。我很好奇您正在实现什么类型的 Web 服务、绑定等。本质上,服务器会缓冲整个消息,然后将其交给处理,这就是为什么在从客户端发送最后一个字节后可能会看到很大的延迟。

对于我正在查看的 Web 服务是 WCF REST 服务的情况,文件在作为流参数传递给 Web 服务方法之前在以下位置进行缓冲:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\86e02ad6\c1702d08\uploads*.post

I believe your request is going over the network. I've discovered Fiddler 2.3.4.4 does not show partial requests but the MS Network Monitor can show the individual packets however not on the localhost loopback (so server and client need to be on different machines if you wish to verify).

I'm running into the same hidden buffering issue here and believe that one of the WCF service settings is not set up correctly on the server for streaming. I'm curious what type of web service you are implementing, bindings, etc. Essentially the server buffers the entire message then hands it off for processing which is why one might see a large delay after the last byte is sent from the client.

For a case I was looking at where the web service was a WCF REST service the file was being buffered at the following location before being passed as a stream argument to a web service method:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\86e02ad6\c1702d08\uploads*.post
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文