HttpClient and how to use Headers, Content-Type and PostAsync

As you might have already heard and tried out with .NET 4.5 (or so) Microsoft blessed us with a new and shiny HttpClient that should be easier to use, support async programming and (that’s best) finally allow the user to set any headers without reverting to some workaround code (cf. WebClient and its underlying classes).

And it is actually true – once you get over the some kind of misleading or lacking documentation. Have a look at your favourite search engine’s search results and you will know what I mean…

Let me show you a quick example that does CRUD (POST/GET/PUT/DELETE) in a synchronous way and also sets the Content-Type, Accept header without reverting to construct a dedicated HttpRequestMessage object:

In case the code is not displayed correctly you can view it at: https://gist.github.com/dfch/7b338046d5e63e3b3106

using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Json;

String Invoke(
  String Method
  ,
  String Uri
  ,
  String Body
  )
{
  HttpClient cl = new HttpClient();
  cl.BaseAddress = new Uri(Uri);
  int _TimeoutSec = 90;
  cl.Timeout = new TimeSpan(0, 0, _TimeoutSec);
  string _ContentType = "application/json";
  cl.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(_ContentType));
  _CredentialBase64 = "RWRnYXJTY2huaXR0ZW5maXR0aWNoOlJvY2taeno="
  cl.DefaultRequestHeaders.Add("Authorization", String.Format("Basic {0}", _CredentialBase64));
  _UserAgent = "d-fens HttpClent";
  # You can actually also set the User-Agent via a built-in property
  cl.DefaultRequestHeaders.Add("User-Agent", _UserAgent);
  # You get the following exception when trying to set the "Content-Type" header like this:
  # cl.DefaultRequestHeaders.Add("Content-Type", _ContentType);
  # "Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects."

  HttpResponseMessage response;
  HttpMethod _Method = new HttpMethod(Method);

  switch (_Method.ToString().ToUpper())
  {
    case "GET":
    case "HEAD":
      # synchronous request without the need for .ContinueWith() or await
      response = cl.GetAsync(Uri).Result;
      break;
    case "POST":
      {
        # Construct an HttpContent from a StringContent
        HttpContent _Body = new StringContent(Body);
        # and add the header to this object instance
        # optional: add a formatter option to it as well
        _Body.Headers.ContentType = new MediaTypeHeaderValue(_ContentType);
        # synchronous request without the need for .ContinueWith() or await
        response = cl.PostAsync(Uri, _Body).Result;
      }
      break;
    case "PUT":
      {
        # Construct an HttpContent from a StringContent
        HttpContent _Body = new StringContent(Body);
        # and add the header to this object instance
        # optional: add a formatter option to it as well
        _Body.Headers.ContentType = new MediaTypeHeaderValue(_ContentType);
        # synchronous request without the need for .ContinueWith() or await
        response = cl.PutAsync(Uri, _Body).Result;
      }
      break;
    case "DELETE":
      response = cl.DeleteAsync(Uri).Result;
      break;
    default:
      throw new NotImplementedException();
      break;
  }
  # either this - or check the status to retrieve more information
  response.EnsureSuccessStatusCode();
  # get the rest/content of the response in a synchronous way
  String content = response.Content.ReadAsStringAsync().Result;

  return content;
}

First thing to mention is: though “DefaultRequestHeaders” is a gettable-only property, it contains properties and methods to actually set indivisual headers.

Second, certain headers cannot be set on this collection. You have to set them on an HttpContent object when you need them and only when you may actually use them, as this is the case with “Content-Type” that cannot be used in a “GET” method. If you stil try to do it, you will get an exception like this:
“Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.”

Third, to easily work around the async behaviour (if you prefer the synchronous way) you simply use the “Result” property of the task object, instead of using “await” or “ContinueWith”. That you will have you wait until the request is finished.

And last, if you have special content types in the body of your message you can also specify this in the PostAsync/PutAsync method where you can easily do this in one of the overloads of the respective method.

Once this is in place HttpClient is just as easy to use as WebClient for example, but with tons of more features and flexibility!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: