문제

I have a WinRT application (8.0, not 8.1, so I can't use Windows.Web.HttpClient) where I am uploading large files to a site. I am using System.Net.Http.HttpClient with the System.Net.Http.Handlers.ProgressMessageHandler from the Microsoft.AspNet.WebApi.Client nuget package for the purposes of tracking progress.

No matter how big a file I upload, I always seem to get the HttpSendProgress event called once, and only once, with 100% progress (and totalBytes == sentBytes). However the file doesn't actually complete uploading to the site until sometime after the event fired, depending on file size and whether I've limited the upload speed etc. The upload does work, but the progress reporting is useless.

I used a network monitoring tool and could see the data being transferred slowly after the progress event was called (when I let the app run after stopping on a break point) - but I only got the event raised one time and with 100% progress before the upload finished.

I presume the HttpClient is writing to some kind of buffer which is happening much more quickly than the actual upload, but I can't figure out how to change/prevent that, or what the point of the ProgressMessageHandler class is if it always works this way.

At the moment the code I'm using looks something like the following;

public static async Task<string> UploadDataAsync(string uploadUrl, byte[] data, string contentTypeHeader, string oauthHeader, Action<long, long?> progressCallback)
{
    var ph = new System.Net.Http.Handlers.ProgressMessageHandler();
    if (progressCallback != null)
    {
        ph.HttpSendProgress += (sender, args) =>
        {
            progressCallback(args.BytesTransferred, args.TotalBytes);
        };
    }

    var client = HttpClientFactory.Create(ph);
    client.Timeout = new TimeSpan(0, 20, 0);

    if (!String.IsNullOrEmpty(oauthHeader)) 
        client.DefaultRequestHeaders.Add("Authorization", oauthHeader);

    var content = new ByteArrayContent(data);
    content.Headers.TryAddWithoutValidation("Content-Type", contentTypeHeader);
    var postResponse = await client.PostAsync(new Uri(uploadUrl), content);
    var result = await postResponse.Content.ReadAsStringAsync();
    if (!postResponse.IsSuccessStatusCode)
    {
        throw new OAuthException(result);
    }
    return result;
}
도움이 되었습니까?

해결책

I ran into the same problem, and the issue was using ByteArrayContent for the Post call. That type doesn't get chunked by the underlying HttpClient (my vague understanding of how this works).

You need to use StreamContent to get progress updates. I used it with a FileStream, which worked perfect. I've seen reports that MemoryStream does not give progress. YMMV.

다른 팁

I recommend chain your both tasks with ContinueWith and use TaskContinuationOptions.OnlyOnRanToCompletion to give the ProgressMessageHandler the chance to report the progress exactly as you want.

Hope this may help.

postResponse.ContinueWith(task =>
     {
         if (task.Result.IsSuccessStatusCode)
         { 
         }
     }, TaskContinuationOptions.OnlyOnRanToCompletion);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top