Async HttpClient in MVC Web apps

Topics: Web Api
Dec 14, 2011 at 7:14 AM

I didn´t give it a try yet, but i´ve read that with the preview 6 the HttpClient has only

Async methods. What is the best practice to use this in an mvc web app (as client for

a web api) without ajax? is this even possible?

 

Regards,

Jakob

Dec 14, 2011 at 6:22 PM
humbrie wrote:

I didn´t give it a try yet, but i´ve read that with the preview 6 the HttpClient has only

Async methods. What is the best practice to use this in an mvc web app (as client for

a web api) without ajax? is this even possible?

 

Regards,

Jakob


I don't know if this is the "correct" way or not, but here is an example of an Async GET and POST

GET:

            List<Contact> contacts = null;
 
            try
            {
                request = new HttpRequestMessage(HttpMethod.Get, new Uri(serviceUrl));
                //Request header for application/xml set at client.  Next line not needed
                //request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(XmlMediaTypeFormatter.DefaultMediaType.MediaType));
 
                response = client.SendAsync(request).Result;
                if (response.IsSuccessStatusCode)
                    contacts = response.Content.ReadAsAsync(typeof(List<Contact>), formatterCollection).Result as List<Contact>;
            }
            catch (Exception ex)
            {
 
                message = ex.Message;
            }
            finally
            {
                request.Dispose();
            }
            return contacts;

------------

POST:

            ObjectContent content = null;
 
            try
            {
                content = new ObjectContent(typeof(Contact), contact, XmlMediaTypeFormatter.DefaultMediaType, formatterCollection);
                response = client.PostAsync(new Uri(serviceUrl), content).Result;
 
                if (response.IsSuccessStatusCode)
                    contact = response.Content.ReadAsAsync(typeof(Contact), formatterCollection).Result as Contact;
            }
            catch (Exception ex)
            {
 
                message = ex.Message;
            }
            finally
            {
                content.Dispose();
            }
            return contact;

-------------

Again, don't know if it is the "correct" way to do it, but it works for me using preview 6.  Hope that helps.

-W

Dec 14, 2011 at 11:15 PM
Edited Dec 14, 2011 at 11:16 PM

Calling .Result on an incomplete task will at best hurt scalability, and at worst could end up deadlocking a thread. (Similar statements can be made about .Wait().)

For MVC 4, we've added support for Task-based actions. Just derive your controller from AsyncController, mark your action method with the "async" keyword, and then use "await" to get the result from the downstream task.
 
Prior to MVC 4, you can map tasks to the XxxAsync/XxxCompleted pattern of MVC async controllers. What you would do is, in the XxxAsync, increment the operations counter by one, and then call .ContinueWith on the task that results from ReadAsAsync to capture the result value and then decrement the outstanding operations counter. Then MVC will call your XxxCompleted method. You can pass the result value to the XxxCompleted method by using the AsyncManager.Parameters collection.
 
Obviously, with MVC 4 + .NET 4.5, the pattern is much simpler, because the resulting code reads imperatively. :)