Coder Perfect

In a HttpClient request, how do you set the Content-Type header?

Problem

I’m attempting to set the Content-Type header of a HttpClient object in order to comply with the requirements of an API I’m calling.

I tried setting the Content-Type like below:

using (var httpClient = new HttpClient())
{
    httpClient.BaseAddress = new Uri("http://example.com/");
    httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
    httpClient.DefaultRequestHeaders.Add("Content-Type", "application/json");
    // ...
}

It lets me add the Accept header, but when I try to add the Content-Type header, it produces an exception:

In a HttpClient request, how do I set the Content-Type header?

Asked by mynameiscoffey

Solution #1

The content type is a content header, not a request header, which is why this is failing. AddWithoutValidation as suggested by Robert Levy may work, but you can also set the content type when creating the request content itself (note that the code snippet adds application/json in two places-for Accept and Content-Type headers):

HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://example.com/");
client.DefaultRequestHeaders
      .Accept
      .Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT header

HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "relativeAddress");
request.Content = new StringContent("{\"name\":\"John Doe\",\"age\":33}",
                                    Encoding.UTF8, 
                                    "application/json");//CONTENT-TYPE header

client.SendAsync(request)
      .ContinueWith(responseTask =>
      {
          Console.WriteLine("Response: {0}", responseTask.Result);
      });

Answered by carlosfigueira

Solution #2

Those who missed John’s response to Carlos’ answer…

req.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

Answered by archgl

Solution #3

Flurl.Http [disclosure: I’m the author] makes this uber-simple if you don’t mind a little library dependency. Its PostJsonAsync function handles both serializing the content and establishing the content-type header, while ReceiveJson handles the response deserialization. You’ll have to specify the accept header manually if it’s required, but Flurl provides a simple way to do so:

using Flurl.Http;

var result = await "http://example.com/"
    .WithHeader("Accept", "application/json")
    .PostJsonAsync(new { ... })
    .ReceiveJson<TResult>();

Flurl is a PCL that uses HttpClient and Json.NET behind the hood, and it works on a variety of platforms.

PM> Install-Package Flurl.Http

Answered by Todd Menier

Solution #4

Make an effort to use TryAddWithoutValidation

  var client = new HttpClient();
  client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");

Answered by SharpCoder

Solution #5

.Net tries to compel you to follow certain rules, such as specifying the Content-Type header only on requests with content (e.g. POST, PUT, etc.). As others have stated, the HttpContent is the preferred method of setting the Content-Type header. Headers. ContentType is an attribute that describes the type of content.

However, some APIs (such as the LiquidFiles Api as of 2016-12-19) require the Content-Type header to be set for a GET request. Even when using TryAddWithoutValidation, Net will not allow you to set this header on the request itself. Furthermore, even if the request is of zero length, you cannot specify a Content for it. Reflection seemed to be the only way for me to get over this. The code is here (in case anyone else wants it).

var field = typeof(System.Net.Http.Headers.HttpRequestHeaders)
    .GetField("invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static) 
  ?? typeof(System.Net.Http.Headers.HttpRequestHeaders) 
    .GetField("s_invalidHeaders", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
if (field != null)
{
  var invalidFields = (HashSet<string>)field.GetValue(null);
  invalidFields.Remove("Content-Type");
}
_client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "text/xml");

Edit:

This field has different names in different versions of the dll, as stated in the comments. The field is currently known as s invalidHeaders in the GitHub source code. As suggested by @David Thompson, the example has been updated to reflect this.

Answered by erdomke

Post is based on https://stackoverflow.com/questions/10679214/how-do-you-set-the-content-type-header-for-an-httpclient-request