225

How do I add a custom header to a HttpClient request? I am using PostAsJsonAsync method to post the JSON. The custom header that I would need to be added is

"X-Version: 1"

This is what I have done so far:

using (var client = new HttpClient()) {
    client.BaseAddress = new Uri("https://api.clickatell.com/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "xxxxxxxxxxxxxxxxxxxx");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    var response = client.PostAsJsonAsync("rest/message", svm).Result;
}
wonea
  • 4,783
  • 17
  • 86
  • 139
Libin Joseph
  • 7,070
  • 5
  • 29
  • 52
  • 3
    Possible duplicate of [Adding Http Headers to HttpClient](http://stackoverflow.com/questions/12022965/adding-http-headers-to-httpclient) – Liam Feb 08 '17 at 09:08
  • @Liam : My question was how to add custom headers. Where as the other question was how to add headers – Libin Joseph Feb 08 '17 at 20:07
  • 6
    I think it has been found that we shouldn't dispose of HttpClient. https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/ – Don Rolling Nov 09 '18 at 17:10

9 Answers9

303

I have found the answer to my question.

client.DefaultRequestHeaders.Add("X-Version","1");

That should add a custom header to your request

Libin Joseph
  • 7,070
  • 5
  • 29
  • 52
  • 92
    No, it does not. This answer should be viewed with caution, since the defaults request headers are sent with each request. You should build your request like @Anubis suggested. DefaultsRequestHeaders should be populated when you create the HttpClient. – Ruhrpottpatriot Aug 05 '17 at 23:30
  • 17
    This only works because you are instantiating a new HttpClient for every request. This is not the way this class should be used: it should be a static field, reused for all requests, at least those to the same endpoint. See documentation and countless blog posts out there. Then, as of course, as @Ruhrpottpatriot points out, changing default headers will affect all requests. – kamilk Nov 21 '18 at 18:00
  • @Ruhrpottpatriot What's wrong with sending the header for every request? – David Klempfner Mar 29 '19 at 03:22
  • @Backwards_Dave See the comment directly above yours – Ruhrpottpatriot Mar 30 '19 at 22:58
  • @kamilk Microsoft's docs specifically recommend disposing the HttpClient after each use, so there's nothing wrong with this. https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=netframework-4.8 – ajbeaven Apr 29 '19 at 10:23
  • 2
    @ajbeaven Nope, that's not what it says. The example at the top of the page shows the Main method of the app, so even though the HttpClient is disposed of, the same instance is used throughout the lifetime of the application, and that is correct in regards to what the documentation says a little bit further down: _'HttpClient is intended to be instantiated once and re-used throughout the life of an application'_. Following this paragraph is an example recommending assigning an HttpClient to a static field. – kamilk Apr 29 '19 at 10:32
  • 1
    @kamilk, you're dead right - that example put me wrong. Thanks for putting me right :) – ajbeaven Apr 29 '19 at 11:06
  • Adding a header to the default headers does not instantiate a new HttpClient, it merely adds another header. To remove the header, use `client.DefaultRequestHeaders.Remove("X-Version");` (or `client.DefaultRequestHeaders.Clear()` to remove all). – Tom Anderson Sep 26 '19 at 00:42
  • Use DefaultRequestHeaders for your app's "global" instance of HttpClient only. "HttpClient is intended to be instantiated once per application" https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=net-5.0. Better to use HttpRequestMessage as described in @Chris Peacock's answer above for granular customisation of specific http request. Both approaches are valid its just HttpRequestMessage gives better control without adverse side effects to other consumers of you client unless DefaultRequestHeaders are really intended to be just that. – Kzrbill Nov 18 '20 at 10:45
  • Since DefaultRequestHeaders is not thread safe, you shouldn't use it if you care about paralellism: https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.defaultrequestheaders?view=net-5.0#remarks – Psddp Jun 16 '21 at 13:41
  • It is mentioned in the documentation that you should instantiate HTTPClient only once per application and should not create a new instance for every request. What is the reason for this recommendation? What is the disadvantage? – Saad Khan Jun 18 '21 at 19:07
  • 2
    Is is ok to use this answer if you're instantiating httpclient using `HttpClientFactory`? – Alex from Jitbit Sep 07 '21 at 10:55
164

Here is an answer based on that by Anubis (which is a better approach as it doesn't modify the headers for every request) but which is more equivalent to the code in the original question:

using Newtonsoft.Json;
...

var client = new HttpClient();
var httpRequestMessage = new HttpRequestMessage
    {
        Method = HttpMethod.Post,
        RequestUri = new Uri("https://api.clickatell.com/rest/message"),
        Headers = { 
            { HttpRequestHeader.Authorization.ToString(), "Bearer xxxxxxxxxxxxxxxxxxx" },
            { HttpRequestHeader.Accept.ToString(), "application/json" },
            { "X-Version", "1" }
        },
        Content = new StringContent(JsonConvert.SerializeObject(svm))
    };

var response = client.SendAsync(httpRequestMessage).Result;
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Chris Peacock
  • 4,107
  • 3
  • 26
  • 24
88
var request = new HttpRequestMessage {
    RequestUri = new Uri("[your request url string]"),
    Method = HttpMethod.Post,
    Headers = {
        { "X-Version", "1" } // HERE IS HOW TO ADD HEADERS,
        { HttpRequestHeader.Authorization.ToString(), "[your authorization token]" },
        { HttpRequestHeader.ContentType.ToString(), "multipart/mixed" },//use this content type if you want to send more than one content type
    },
    Content = new MultipartContent { // Just example of request sending multipart request
        new ObjectContent<[YOUR JSON OBJECT TYPE]>(
            new [YOUR JSON OBJECT TYPE INSTANCE](...){...}, 
            new JsonMediaTypeFormatter(), 
            "application/json"), // this will add 'Content-Type' header for the first part of request
        new ByteArrayContent([BINARY DATA]) {
            Headers = { // this will add headers for the second part of request
                { "Content-Type", "application/Executable" },
                { "Content-Disposition", "form-data; filename=\"test.pdf\"" },
            },
        },
    },
};
Anubis
  • 2,484
  • 2
  • 22
  • 33
  • 70
    answer is extremely confusing ... why are you bringing in code for documents, blank.pdf, etc? instantiating bytearray classes to pass custom headers within the Content param? – heug Nov 26 '18 at 15:51
  • 2
    @heug Well. If you are looking for header you can see it. Content is present here in order to complete the picture because you most likely want to add some content to your request. And in order to not be tedious the content is complicated and contain both JSON and binary data. – Anubis Nov 26 '18 at 20:20
  • 2
    it just seems more straightfoward to do it like this: create StringContent using your content JSON, create a HTTP message with your method and URI, then add headers like message.Headers.Add("x":"y") .... then pass those into a response var like "var response = await httpClient.SendAsync(message);" – heug Nov 26 '18 at 22:13
  • @heug I will remember this for the furute. Thanks! – Anubis Nov 27 '18 at 12:30
  • 8
    Which line in the above accepted answer actually implements the header that the OP requested, X-Version? Why is this considered the accepted answer? – Ron Mar 21 '19 at 19:32
  • Sorry. I had to prittify my answer long ago. Hope it is less confusing now. – Anubis Apr 06 '20 at 13:01
  • really why? why making a HTTP request with c# has to be more difficult than c or more difficult than do it with a simple TCP socket? all this headers will gather in payload as simple string and lines, so i think this much of classes and abstracts are just waste of time. – FARHAD AFSAR Jun 01 '20 at 17:03
  • 2
    I found this answer really helpful, thanks for the extra examples. – Alex from Jitbit Oct 08 '21 at 23:14
9

There is a Headers property in the HttpRequestMessage class. You can add custom headers there, which will be sent with each HTTP request. The DefaultRequestHeaders in the HttpClient class, on the other hand, sets headers to be sent with each request sent using that client object, hence the name Default Request Headers.

Hope this makes things more clear, at least for someone seeing this answer in future.

mayo
  • 3,845
  • 1
  • 32
  • 42
BobTheBuilder
  • 109
  • 1
  • 3
  • 2
    No, does not make it any clearer. In both cases you are saying you are sending headers on every request - So what is the difference? – joedotnot Jan 24 '19 at 06:21
  • 8
    `Headers` is a property of an individual `HttpRequestMessage` object. Thus you can create different messages with different headers. `DefaultRequestHeaders` is a property of the `HttpClient` object; if multiple messages are sent through a given `HttpClient`, all such messages will all have the same `DefaultRequestHeaders` added to the message's individual headers. – Ross Presser Mar 11 '19 at 15:33
3

I have added x-api-version in HttpClient headers as below :

var client = new HttpClient(httpClientHandler)
{
    BaseAddress = new Uri(callingUrl)
};
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Add("x-api-version", v2);
Aung San Myint
  • 181
  • 2
  • 7
1

My two cents. I agree with heug. The accepted answer is a mind bender. Let's take a step back.

Default headers apply to all requests made by a particular HttpClient. Hence you would use default headers for shared headers.

_client.DefaultRequestHeaders.UserAgent.ParseAdd(_options.UserAgent);          

However, we sometimes need headers specific to a certain request. We would therefore use something like this in the method:

public static async Task<HttpResponseMessage> GetWithHeadersAsync(this 
    HttpClient httpClient, string requestUri, Dictionary<string, string> headers)
    {
        using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri))
        {
            foreach(var header in headers)
            {
                request.Headers.Add(header.Key, header.Value);
            }

            return await httpClient.SendAsync(request);
        }
    }

If you only need one additional non-default header you would simply use:

request.Headers.Add("X-Version","1")

For more help: How to add request headers when using HttpClient

AndyA
  • 11
  • 1
1

Also you can use HttpClient.PostAsync method:

using (HttpClient http_client = new HttpClient())
{
   StringContent string_content = new StringContent(JsonSerializer.Serialize("{\"field\":\"field_value\"}"));
   string_content.Headers.Add("X-Version","1");
   using (HttpResponseMessage response = await http_client.PostAsync("http://127.0.0.1/apiMethodName", string_content))
   {
      if (response.IsSuccessStatusCode)
      {
         Console.WriteLine($"Response status code: {response.StatusCode}");
      }
      else
      {
         Console.WriteLine($"Error status code: {response.StatusCode}");
      }
   }
}
Ramil Shavaleev
  • 364
  • 3
  • 12
0

Just in case someone is wondering how to call httpClient.GetStreamAsync() which does not have an overload which takes HttpRequestMessage to provide custom headers you can use the above code given by @Anubis and call

await response.Content.ReadAsStreamAsync()

Especially useful if you are returning a blob url with Range Header as a FileStreamResult

CCRider
  • 1
  • 1
0

You can use System.Net.Http.Json.JsonContent, which is what PostAsJsonAsync() does internally:

var jsonContent = JsonContent.Create(payload);
jsonContent.Headers.Add("X-custom-header", "Value");

var resp = await httpClient.PostAsync(uri, jsonContent);

This has advantages above other alternatives:

  • It uses optimized UTF-8 serialization with the applications configured behaviour.
  • It does not set DefaultRequestHeaders, which might affect other, unrelated queries.
PeterB
  • 886
  • 10
  • 18