4

我一直在尝试跟踪文件上传的进度,但一直处于死胡同(从 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和设置:ContentLength

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

直到整个文件被写入流并且在它开始时已经显示了完整的进度(我正在使用提琴手来验证这一点),该请求才会开始。我也尝试设置SendChunked为 true (有和没有设置ContentLength)。似乎数据在通过网络发送之前仍会被缓存。

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

4

2 回答 2

3

更新:

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

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);
    }
于 2011-01-30T20:31:51.647 回答
1

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

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

对于一个案例,我正在查看 Web 服务是 WCF REST 服务的位置,该文​​件在作为流参数传递给 Web 服务方法之前被缓冲在以下位置:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\root\86e02ad6\c1702d08\uploads*.post
于 2011-07-01T21:09:50.993 回答