Webclient + UploadStringAsync + События: UploadProgressChanged / DownloadProgressChanged - PullRequest
1 голос
/ 05 апреля 2019

Мне нужно связаться со службой REST.

По некоторым причинам я должен использовать запрос POST для получения данных JSON из этой службы. (Я думаю, что он должен использовать запрос GET, но это не под моим контролем, и я не могу его изменить ...)

Ответ на один запрос составляет около 25-30 МБ. Поскольку ответ большой, я решил использовать метод WebClient и метод UploadStringAsync.

private string jsonResult = "";

void test()
{
    string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(username + ":" + passowrd));  
    using (System.Net.WebClient client = new System.Net.WebClient())
    {
        client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
        client.UploadProgressChanged += new UploadProgressChangedEventHandler(client_UploadProgressHandler);
        client.UploadStringCompleted += new UploadStringCompletedEventHandler(client_UploadStringCompletedHandler);                
        client.Headers.Add("Authorization", "Basic " + credentials);
        client.Encoding = System.Text.Encoding.UTF8;
        Uri uri = new Uri(https://demoapi.org/stuff/prod/0);

        client.UploadStringAsync(uri, "POST", "");
    }
}

private void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
    Console.WriteLine("DOWNLOAD_PROGRESS!");
    Console.WriteLine("Status {0} of {1} bytes. {2} % complete", e.BytesReceived, e.TotalBytesToReceive, e.ProgressPercentage);
}

private static void client_UploadProgressHandler(object sender, UploadProgressChangedEventArgs e)
{
    Console.WriteLine("UPLOAD_PROGRESS!");
    Console.WriteLine("Status {0} of {1} bytes. {2} % complete, {3} of {4} bytes. {5} % complete", e.BytesReceived, e.TotalBytesToReceive, e.ProgressPercentage, e.BytesSent, e.TotalBytesToSend, e.ProgressPercentage);
}

private void client_UploadStringCompletedHandler(Object sender, UploadStringCompletedEventArgs e)
{
    Console.WriteLine("UPLOAD_COMPLETED!");
    jsonResult = e.Result;
}

С приведенным выше кодом консоль много раз показывает сообщение UPLOAD_PROGRESS! и однажды сообщение UPLOAD_COMPLETED! Тем не менее, я не вижу сообщения DOWNLOAD_PROGRESS!

UPLOAD_PROGRESS!
UPLOAD_PROGRESS!
....    
UPLOAD_PROGRESS!
UPLOAD_COMPLETED!

Вот мои вопросы:

1) Могу ли я (действительно) подписаться на событие «UploadProgressChanged» с помощью метода webclient.UploadStringAsync?

В документации Microsoft не говорится, что UploadProgressChanged доступен для UploadStringAsync, но в любом случае кажется, что он работает с кодом выше.

https://docs.microsoft.com/en-us/dotnet/api/system.net.webclient.uploadprogresschanged?view=netframework-4.7.2

https://docs.microsoft.com/en-us/dotnet/api/system.net.webclient.uploadstringasync?view=netframework-4.7.2

Я также посмотрел справочный ресурс Microsoft, но не до конца его понимаю. Похоже, что делегат UploadProgressChanged отсутствует в методе UploadStringAsync.

https://referencesource.microsoft.com/#System/net/System/Net/webclient.cs,d15a560fedc713da,references

Итак, мне интересно, правильно ли использовать «UploadProgressChanged» с webclient.UploadStringAsync.

2) Можно ли подписаться на событие «DownloadProgressChanged» с помощью метода webclient.UploadStringAsync?

3) Как я понимаю, веб-клиент использует WebRequest и WebResponse под капотом. Можно ли получить ход выполнения обоих запросов?

Я спрашиваю об этом, потому что иногда тело запроса большое, а иногда большой ответ.

4) Если DownloadProgressChangedEvent недоступен, то Как я могу сообщить о прогрессе части WebResponse POST-запроса «UploadStringAsync»?

Спасибо

1 Ответ

1 голос
/ 10 апреля 2019

Ваш код выше загружает , поэтому он не может получить событие DownloadProgressChanged .

Правило - все асинхронные методы Download или Upload вызывают соответствующие события, измененные в процессе Download или Upload. Под сценой UploadStringAsync использует тот же код, что и UploadDataAsync (поскольку строка представляет собой массив байтов по модулю кодировки символов).

Не асинхронные методы не вызывают события прогресса.

Если вам нужен доступ к базовому WebRequest, просто создайте класс, производный от WebClient, и переопределите защищенный виртуальный метод GetWebRequest (адрес Uri) , например:

public class MyWebClient : WebClient
{
    protected override WebRequest GetWebRequest(Uri address)
    {
        var request = base.GetWebRequest(address);
        // do something with the request
        // BTW, this is how you can change timeouts or use cookies
        return request;
    }
}

Обратите внимание, что вы также можете использовать более современный HttpClient (полностью кроссплатформенный, фреймворк и т. Д.) Вместо WebClient.

...