3

I am trying to use HttpWebRequest and HttpWebResonse asynchronously in a WinForms application without blocking my UI thread.

I saw this similar SO Question which explains how to do it. However, I am not 100% sure the accepted answer is the correct way to do it. The accepted answer is using BeginGetResponse.

According to the MSDN documentation:

The BeginGetResponse method requires some synchronous setup tasks to complete (DNS resolution, proxy detection, and TCP socket connection, for example) before this method becomes asynchronous. As a result, this method should never be called on a user interface (UI) thread because it might take some time, typically several seconds.

Can someone please provide me with the correct way to do this. Here is my C# function that I'm trying to make work "properly" without blocking my UI thread:

    private IDictionary<string, object> CreateWebRequest(string endPoint, string method, string data, bool addAuthHeader)
    {
        var req = (HttpWebRequest)WebRequest.Create(endPoint);
        req.Method = method;
        if (addAuthHeader)
        {
            req.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + _accessToken.AccessToken);
        }

        if (!string.IsNullOrEmpty(data))
        {
            var utfenc = new UTF8Encoding();
            byte[] buffer = utfenc.GetBytes(data);
            req.ContentLength = buffer.Length;
            req.ContentType = "application/x-www-form-urlencoded";

            using (Stream strm = req.GetRequestStream())
            {
                strm.Write(buffer, 0, buffer.Length);
                strm.Close();
            }
        }

        HttpWebResponse response = null;
        try
        {
            response = (HttpWebResponse)req.GetResponse();
        }
        catch (WebException e)
        {
            if (_accessToken == null)
            {
                throw;
            }
            var responseError = (HttpWebResponse)e.Response;
            if (responseError.StatusCode == HttpStatusCode.Unauthorized)
            {
                var stackTrace = new StackTrace();
                var q = stackTrace.GetFrame(1).GetMethod().Name;
                RefreshAccessCode();

                req = (HttpWebRequest)WebRequest.Create(endPoint);
                req.Method = method;
                if (addAuthHeader)
                {
                    req.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + _accessToken.AccessToken);
                }
                response = (HttpWebResponse)req.GetResponse();
            }
        }

        string jsonResponse = null;

        if (response != null)
            using (Stream stream = response.GetResponseStream())
            {
                if (stream != null)
                {
                    using (var reader = new StreamReader(stream))
                    {
                        jsonResponse = reader.ReadToEnd();
                    }
                }
            }

        return DeserializeResponse(jsonResponse);
    }
1
  • isn't @Isak's answer to the other SO question you linked what you're looking for? Commented Feb 26, 2013 at 21:14

2 Answers 2

3

If you're open to something besides WebRequest, I'm a fan of System.Net.WebClient. It uses System.Threading.Tasks instead of BeginGetResponse() and EndGetResonse().

public async Task<Dictionary<string, object>> CreateWebRequest(string endPoint, string method, string data, bool addAuthHeader)
{
    WebClient client = new WebClient();

    if (addAuthHeader)
    {
        client.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + _accessToken.AccessToken);
    }

    byte[] buffer = null;

    if (!string.IsNullOrEmpty(data))
    {
        var utfenc = new UTF8Encoding();
        buffer = utfenc.GetBytes(data);
    }
    else
    {
        buffer = new byte[0];
    }

    return await client.UploadDataTaskAsync(endPoint, method, buffer)
        .ContinueWith((bytes) =>
            {
                string jsonResponse = null;

                using (var reader = new StreamReader(new MemoryStream(bytes)))
                {
                    jsonResponse = reader.ReadToEnd();
                }

                return DeserializeResponse(jsonResponse);
            });
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

It should be new MemoryStream(bytes.Result)
0

To use your existing code, just add a method that is intended to execute on the UI thread, and create your web request on a separate thread. When the web request is complete you call the final method on the UI thread. So, a simple version would be:

//do some stuff that wont block the ui thread here
ThreadPool.QueueUserWorkItem((o) => 
{
    IDictionary<string, object> result = 
        CreateWebRequest("lalala", "lol", "butts", true);
    BeginInvoke(OnAsyncWebRequestComplete, result);
}, null);

private void OnAsyncWebRequestComplete(IDictionary<string, object> result)
{
    //do some stuff on the UI thread here
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.