How do you set the Content-Type header for an HttpClient request?

1,118,396

Solution 1

The content type is a header of the content, not of the request, 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);
      });

Solution 2

For those who didn't see Johns comment to carlos solution ...

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

Solution 3

If you don't mind a small library dependency, Flurl.Http [disclosure: I'm the author] makes this uber-simple. Its PostJsonAsync method takes care of both serializing the content and setting the content-type header, and ReceiveJson deserializes the response. If the accept header is required you'll need to set that yourself, but Flurl provides a pretty clean way to do that too:

using Flurl.Http;

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

Flurl uses HttpClient and Json.NET under the hood, and it's a PCL so it'll work on a variety of platforms.

PM> Install-Package Flurl.Http

Solution 4

try to use TryAddWithoutValidation

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

Solution 5

.Net tries to force you to obey certain standards, namely that the Content-Type header can only be specified on requests that have content (e.g. POST, PUT, etc.). Therefore, as others have indicated, the preferred way to set the Content-Type header is through the HttpContent.Headers.ContentType property.

With that said, certain APIs (such as the LiquidFiles Api, as of 2016-12-19) requires setting the Content-Type header for a GET request. .Net will not allow setting this header on the request itself -- even using TryAddWithoutValidation. Furthermore, you cannot specify a Content for the request -- even if it is of zero-length. The only way I could seem to get around this was to resort to reflection. The code (in case some else needs it) is

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:

As noted in the comments, this field has different names in different versions of the dll. In the source code on GitHub, the field is currently named s_invalidHeaders. The example has been modified to account for this per the suggestion of @David Thompson.

Share:
1,118,396
mynameiscoffey
Author by

mynameiscoffey

If it ain't broke, break it!

Updated on July 15, 2022

Comments

  • mynameiscoffey
    mynameiscoffey almost 2 years

    I'm trying to set the Content-Type header of an HttpClient object as required by an API I am 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 allows me to add the Accept header but when I try to add Content-Type it throws the following exception:

    Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.

    How can I set the Content-Type header in a HttpClient request?

  • dhara tcrails
    dhara tcrails over 11 years
    Alternatively, Response.Content.Headers will work most of the time.
  • jerhewet
    jerhewet over 9 years
    @AshishJain Most of the SO answers I've seen involving Response.Content.Headers for the ASP.Net Web API haven't worked either, but you can easily set it using HttpContext.Current.Response.ContentType if you need to.
  • Ashish-BeJovial
    Ashish-BeJovial over 9 years
    @jerhewet i used in following way which worked for me. var content = new StringContent(data, Encoding.UTF8, "application/json");
  • Julian Reschke
    Julian Reschke almost 9 years
    Content-Type is a property of an HTTP message with payload; it has nothing to do with request vs response.
  • Matteo Defanti
    Matteo Defanti over 8 years
    It made difference downloading a pdf. From the phone it tried to download an HTML. After converting the extension the file was normally encoded.
  • John Meyer
    John Meyer almost 8 years
    I had to throw .ToString() on the end, but yes this worked for a WCF service implementation.
  • Bill Noel
    Bill Noel over 7 years
    Interesting. I tried creating a new StringContent with the three parameters and it didn't work. I then manually: request.Content.Headers.Remove("Content-Type") and then: request.Content.Headers.Add("Content-Type", "application/query+json") and it worked. Odd.
  • prem
    prem over 7 years
    Not working with .Net Framework version 4.0, System.Net.Http version 2.2.29.0 but working with 2.0.0.0
  • Vlado Pandžić
    Vlado Pandžić about 7 years
    How to send if content is application/x-www-form-urlencoded?
  • David Thompson
    David Thompson about 7 years
    This field is now s_invalidHeaders so using the following ensures compatibility: 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);
  • Mahmoud Samy
    Mahmoud Samy about 7 years
    StringContent should be dispossed
  • Jay
    Jay almost 7 years
    Added an answer related to this for .NET Core 1.1
  • Halter
    Halter almost 7 years
    What is the "relativeAddress" bit?
  • Gerard ONeill
    Gerard ONeill almost 7 years
    Thanks, Jay -- Not using core, and will use erdomke's answer. I appreciate knowing that all reasonable avenues have been tried :).
  • Tarek El-Mallah
    Tarek El-Mallah over 6 years
    not working .net 4 ({"Cannot send a content-body with this verb-type."})
  • Jay
    Jay over 6 years
    @TarekEl-Mallah Yes - please read the comments in my answer. The whole point of my post was to illustrate that it doesn't work in .NET 4, but it does work in .NET core (they are not the same thing). You will have to see erdomeke's answer to the OP's question to be able to hack it to work in .NET 4.
  • Tarek El-Mallah
    Tarek El-Mallah over 6 years
    I applied that fix, and there is a major error happened, if there is something wrong with the HTTP request, the whole further requests fail, any network traffic will fail in the whole iis service. My advice, do not use that at all and search for alternative solution.
  • erdomke
    erdomke over 6 years
    I am confused on how this code would cause the catastrophic errors you describe. Can you provide more details on your use case and the errors you are receiving?
  • Martin Lietz
    Martin Lietz over 6 years
    not working gives me a 'Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.'
  • Martin Lietz
    Martin Lietz over 6 years
    not working gives me a 'Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.'
  • urbanhusky
    urbanhusky over 6 years
    HttpClient should be reused (static) and used as such (do not set base address, default request headers etc.)
  • BradLaney
    BradLaney almost 6 years
    This is bad. You should re-use HttpClient. DefaultRequestHeaders are only supposed to be used if you're using the HttpClient for many different related issues. HttpClient's are supposed to be closely related to instantiated as singletons. Aka re-used.
  • Alejandro
    Alejandro almost 6 years
    Can you give a small explanation of what it does?
  • KansaiRobot
    KansaiRobot almost 6 years
    AddWithoutValidation does not exist
  • Randall Flagg
    Randall Flagg over 5 years
    The first line fails with CS0144: "Cannot create an instance of the abstract class or interface 'HttpContent'"
  • AlfeG
    AlfeG over 5 years
    Wow. Even more wow, that Asp.net WebApi GET methods require Content-Type to be explicitly specified =(
  • mmix
    mmix over 5 years
    Holly molly, I cannot believe I have to resort to this. Since when do the .NET framework devs it needy to hold my hand in what I can add to Http header section? Abominable.
  • art24war
    art24war over 5 years
    and then HttpMessageHandler handler = new WebRequestHandler(); HttpResponseMessage result; using (var client = (new HttpClient(handler, true))) { result = client.PostAsync(fullUri, content).Result; }
  • granadaCoder
    granadaCoder over 5 years
    I will eventually figure out what object type "req" is ... by trial and error........BUT it would be great to show that. Thank you for your consideration.
  • granadaCoder
    granadaCoder over 5 years
    System.Net.Http.HttpRequestMessage from "microsoft.netcore.app\2.1.0\ref\netcoreapp2.1\System.Net.Ht‌​tp.dll" is where I found it.
  • granadaCoder
    granadaCoder over 5 years
    Those of you reporting "working" or "not working", HttpClient is a very ambiguous object these days. Please report the fullname(space) and .dll assembly it is coming from.
  • I Stand With Israel
    I Stand With Israel over 5 years
    Just so folks know, using MediaTypeHeaderValue will return an error if attempting to set the charset, like so; response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/xml; charset=utf-8");
  • joedotnot
    joedotnot over 5 years
    Johns comment to Carlo's solution said Response.Content.Headers, but you are using req.Content.Headers ? i.e. Request vs Response ?
  • ps2goat
    ps2goat about 5 years
    the Misused header name error is confirmed with dotnet core 2.2. I had to use @carlosfigueira's answer stackoverflow.com/a/10679340/2084315.
  • nldev
    nldev almost 5 years
    I was experiencing the same issue. Your solution seems to be the only one working for me (Calling an external API requiring Content-Type on get requests.) Thanks!
  • GDroid
    GDroid almost 5 years
    Awesome hack. Works for me, however, first time it does't apply the JSON header, but all subsequent calls it does. Anyone had similar behavior? I did work around it but any good hack around it?
  • Tim Davis
    Tim Davis over 4 years
    relativeAddress is the url
  • BVernon
    BVernon about 4 years
    I was getting errors trying to post with "application/vnd.api+json". Was just about to give up when I saw this and it fixed my issue.
  • DesertFoxAZ
    DesertFoxAZ about 4 years
    stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json"); also works
  • DesertFoxAZ
    DesertFoxAZ about 4 years
    I've noticed that if I use this in my API which calls a 3rd-party API the first request is successful but subsequent ones fail and I can't get it working again unless I restart IIS.
  • phoenixstudio
    phoenixstudio over 3 years
    please edit your question, try to explain the issue and your solition (without imojis)
  • danyloid
    danyloid over 3 years
    Thanks for posting it, it is quite unfortunate the validation is enforced to this extent
  • martinp999
    martinp999 over 3 years
    To be clear, System.Net.Http has provided a poor implementation here. Content-Type is an HTTP request header and an implementation that suggests otherwise is misleading and confusing. However, as you are using dotnet, you have to live with it. (developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-T‌​ype).
  • yoel halb
    yoel halb about 3 years
    Although this is a great answer, it no longer works in newer .Net versions, see my answer at stackoverflow.com/a/66449794/640195 for an updated answer
  • ProgrammingLlama
    ProgrammingLlama about 3 years
    Why is all this reflection necessary? It's the content object that dictates Content-Type, and you can add a content object on GET requests as well as POST, PUT, etc. If you don't have a content object (body) then Content-Type is an irrelevant header.
  • yoel halb
    yoel halb about 3 years
    @John There are frameworks including Microsoft own frameworks that require the header even for a Get and even when there is no Content, don't ask me why.. and why their client removes it when their server expects it...
  • yoel halb
    yoel halb about 3 years
    I guess there is a fight between the Microsoft teams and we are the monkeys in the middle...
  • ProgrammingLlama
    ProgrammingLlama about 3 years
    Unless the Content-Length header presents a problem, isn't it better just to create a derived HttpContent object that allows you to specify the header rather than doing all this reflection?
  • Simple
    Simple about 3 years
    @carlosfigueira According to Microsoft Documentation regarding the DefaultRequestHeaders it says: "Headers set on this property don't need to be set on request messages again." So you should not add Content-Type again in the HttpRequestMessage, just StringContent(String, Encoding) should be enough.
  • codeMonkey
    codeMonkey almost 3 years
    This only works with .NET Core, not .NET Framework.
  • kennydust
    kennydust over 2 years
    @billnoel's answer should be the correct answer
  • Craig Brown
    Craig Brown over 2 years
    For JSON content, as of .NET 5 you can do: requestMessage.Content = JsonContent.Create(new {Name = "John Doe", Age = 33}); and the Content-Type is set automatically.
  • Garr Godfrey
    Garr Godfrey over 2 years
    problem I'm running into is that PostAsJsonAsync doesn't set the Content-type header!!
  • nuander
    nuander about 2 years
    The problem with using this is that it breaks all the other API calls that didn't have this problem. I think because of the BindingFlags.Static which is required to make this work.