Theory
They serve different purpose:
Practice
Try to set Content-Type on the Request
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, address);
request.Headers.Add("Content-Type", "application/json");
This will produce the following exception:
System.InvalidOperationException: 'Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.'
Try to set Accept on Content
var content = new StringContent("Test", Encoding.UTF8);
content.Headers.Add("Accept","application/json");
This will produce the following exception:
System.InvalidOperationException: 'Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.'
Try to set the same arbitrary header at both places:
const string headerKey = "A", requestHeaderValue = "B", contentHeaderValue = "C";
var content = new StringContent("Test", Encoding.UTF8);
content.Headers.Add(headerKey, requestHeaderValue);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, address);
request.Headers.Add(headerKey, contentHeaderValue);
This will not produce any exception.
Which value is passed to the downstream?
In order to be able answer this question I will use the WireMock.Net nuget package to run a mock server.
const string address = "http://localhost:9000", route = "/";
var server = WireMockServer.Start(new WireMockServerSettings { Urls = new[] { address } });
server
.Given(Request.Create()
.WithPath(route)
.WithHeader(headerKey, new ExactMatcher(requestHeaderValue))
.UsingPost())
.RespondWith(Response.Create()
.WithBody("From Request header")
.WithStatusCode(200));
server
.Given(Request.Create()
.WithPath(route)
.WithHeader(headerKey, new ExactMatcher(contentHeaderValue))
.UsingPost())
.RespondWith(Response
.Create()
.WithBody("From Content header")
.WithStatusCode(200));
- Here I have defined a mock server which listens on the 9000 port
- It has a single endpoint on the
/ route and it anticipates a POST request
- Depending on the
headerKey value it may respond
- either with
From Request header
- or with
From Content header
If I send a request where the same header key is set on both objects then I will receive the following response:
From Request header
Does ordering matter?
What if I switch the order of the header key assignments?
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, address);
request.Headers.Add(headerKey, contentHeaderValue);
var content = new StringContent("Test", Encoding.UTF8);
content.Headers.Add(headerKey, requestHeaderValue);
The result will be the same: From Request header.
For the sake of completeness here is the full source code:
static readonly HttpClient httpClient = new HttpClient();
static async Task Main(string[] args)
{
const string headerKey = "A", requestHeaderValue = "B", contentHeaderValue = "C";
const string address = "http://localhost:9000", route = "/";
var server = WireMockServer.Start(new WireMockServerSettings { Urls = new[] { address } });
server
.Given(Request.Create()
.WithPath(route)
.WithHeader(headerKey, new ExactMatcher(requestHeaderValue))
.UsingPost())
.RespondWith(Response.Create()
.WithBody("From Request header")
.WithStatusCode(200));
server
.Given(Request.Create()
.WithPath(route)
.WithHeader(headerKey, new ExactMatcher(contentHeaderValue))
.UsingPost())
.RespondWith(Response
.Create()
.WithBody("From Content header")
.WithStatusCode(200));
var request = new HttpRequestMessage(HttpMethod.Post, address);
request.Headers.Add(headerKey, contentHeaderValue);
var content = new StringContent("Test", Encoding.UTF8);
content.Headers.Add(headerKey, requestHeaderValue);
var response = await httpClient.SendAsync(request);
var headerSource = await response.Content.ReadAsStringAsync();
Console.WriteLine(headerSource);
}