9

Up until now, I've been making synchronous HttpWebRequest calls in WinForms applications. I want to start doing it asynchronously so as to not block the UI thread and have it hang. Therefore, I am attempting to switch to HttpClient, but I am also new to async and tasks and don't quite get it, yet.

I can launch the request and get a response and isolate the data I want (result, reasonPhrase, headers, code) but don't know how to get that back for display in textBox1. I also need to capture ex.message and return to the form if a timeout or cannot connect message occurs.

Every single example I see has the values written to Console.WriteLine() at the point they are available, but I need them returned back to the form for display and processing and have a hard time understanding how.

Here's a simple example:

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.
                }
            }
        }
    }
}

Any helpful hints or advice?

LordChariot
  • 543
  • 1
  • 6
  • 10
  • 4
    Create a custom class where you store the results from your call. Then return Task from DownloadPageAsync – Steve Jul 13 '17 at 19:20

1 Answers1

13

create a model to hold the data you want to return

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

Avoid using async void methods. Convert the method to async Task and call it in the event handler where it is allowed.

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

The HttpClientshould also not be created every time the download is called.

Refer to What is the overhead of creating a new HttpClient per call in a WebAPI client?

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • I understand about the using(HttpClient...) now. I think you are right and using a static client is best for this purpose. I was thinking about trying to launch simultaneous (only about 4) requests, but the feeling went away. – LordChariot Jul 13 '17 at 20:19