4

ファイルのアップロードの進行状況を追跡しようとしましたが、行き止まりに陥り続けています (Web ページではなく 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 ネットワーク モニターは個々のパケットを表示できますが、ローカルホスト ループバックでは表示できません (検証する場合は、サーバーとクライアントを別のマシンに配置する必要があります)。

ここで同じ隠れたバッファリングの問題が発生しており、ストリーミング用のサーバーで WCF サービス設定の 1 つが正しく設定されていないと考えています。実装している 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 に答える