Как вернуть асинхронные ответы HttpClient обратно в WinForm?

До сих пор я выполнял синхронные вызовы HttpWebRequest в приложениях WinForms. Я хочу начать делать это асинхронно, чтобы не блокировать поток пользовательского интерфейса и не зависать. Поэтому я пытаюсь переключиться на HttpClient, но я также новичок в асинхронности и задачах и пока не совсем понимаю.

Я могу запустить запрос и получить ответ и изолировать нужные мне данные (результат, ReasonPhrase, заголовки, код), но не знаю, как вернуть их для отображения в textBox1. Мне также нужно захватить ex.message и вернуться к форме, если происходит тайм-аут или сообщение о невозможности подключения.

В каждом отдельном примере, который я вижу, значения записываются в Console.WriteLine() в тот момент, когда они доступны, но мне нужно, чтобы они возвращались обратно в форму для отображения и обработки, и мне трудно понять, как это сделать.

Вот простой пример:

namespace AsyncHttpClientTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void button1_Click(object sender, EventArgs e)
        {
            textBox1.Text = "calling Test()...\r\n";
            DownloadPageAsync();

            // need to get from DownloadPageAsync here: result, reasonPhrase, headers, code 

            textBox1.AppendText("done Test()\r\n");
        }
        static async void DownloadPageAsync()
        {
            // ... Use HttpClient.
            using (HttpClient client = new HttpClient())
            {
                try
                {
                    using (HttpResponseMessage response = await client.GetAsync(new Uri("http://192.168.2.70/")))
                    {
                        using (HttpContent content = response.Content)
                        {
                            // need these to return to Form for display
                            string result = await content.ReadAsStringAsync();
                            string reasonPhrase = response.ReasonPhrase;
                            HttpResponseHeaders headers = response.Headers;
                            HttpStatusCode code = response.StatusCode;
                        }
                    }
                }
                catch (Exception ex)
                {
                    // need to return ex.message for display.
                }
            }
        }
    }
}

Любые полезные советы или советы?


person LordChariot    schedule 13.07.2017    source источник
comment
Создайте собственный класс, в котором вы будете хранить результаты своего звонка. Затем верните Task‹YourCustomClass› из DownloadPageAsync.   -  person Steve    schedule 13.07.2017


Ответы (1)


создайте модель для хранения данных, которые вы хотите вернуть

public class DownloadPageAsyncResult {
    public string result { get; set; } 
    public string reasonPhrase { get; set; } 
    public HttpResponseHeaders headers { get; set; }
    public HttpStatusCode code { get; set; }
    public string errorMessage { get; set; }
}

Избегайте использования async void методов. Преобразуйте метод в async Task и вызовите его в обработчике событий, где это разрешено.

private async void button1_Click(object sender, EventArgs e) {
    textBox1.Text = "calling Test()...\r\n";
    var result = await DownloadPageAsync();

    // Access result, reasonPhrase, headers, code here

    textBox1.AppendText("done Test()\r\n");
}

static HttpClient client = new HttpClient();
static async Task<DownloadPageAsyncResult> DownloadPageAsync() {
    var result = new DownloadPageAsyncResult();
    try {
        using (HttpResponseMessage response = await client.GetAsync(new Uri("http://192.168.2.70/"))) {
            using (HttpContent content = response.Content) {
                // need these to return to Form for display
                string resultString = await content.ReadAsStringAsync();
                string reasonPhrase = response.ReasonPhrase;
                HttpResponseHeaders headers = response.Headers;
                HttpStatusCode code = response.StatusCode;                    

                result.result = resultString;
                result.reasonPhrase = reasonPhrase;
                result.headers = headers;
                result.code = code;
            }
        }
    } catch (Exception ex) {
        // need to return ex.message for display.
        result.errorMessage = ex.Message;
    }
    return result;
}

HttpClient также не следует создавать каждый раз, когда вызывается загрузка.

См. раздел Каковы накладные расходы на создание нового HttpClient для каждого вызова в клиенте WebAPI?

person Nkosi    schedule 13.07.2017
comment
Теперь я понимаю использование (HttpClient...). Я думаю, что вы правы, и для этой цели лучше всего использовать статический клиент. Думал попробовать запустить одновременные (всего около 4-х) запросов, но ощущение ушло. - person LordChariot; 13.07.2017