I have an issue with HttpClient.PostAsJsonAsync()
In addition to "application/json" in the "Content-Type" header the method also adds "charset=utf-8"
so the header looks like this:
Content-Type: application/json; charset=utf-8
While ASP.NET WebAPI doesn't have any issue with this header, i've found that other WebAPIs I work against as a client don't accept request with this header, unless it's only application/json.
Is there anyway to remove the "charset=utf-8" from Content-Type when using PostAsJsonAsync(), or should I use another method?
SOLUTION: Credits to Yishai!
using System.Net.Http.Headers;
public class NoCharSetJsonMediaTypeFormatter : JsonMediaTypeFormatter
{
public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType)
{
base.SetDefaultContentHeaders(type, headers, mediaType);
headers.ContentType.CharSet = "";
}
}
public static class HttpClientExtensions
{
public static async Task<HttpResponseMessage> PostAsJsonWithNoCharSetAsync<T>(this HttpClient client, string requestUri, T value, CancellationToken cancellationToken)
{
return await client.PostAsync(requestUri, value, new NoCharSetJsonMediaTypeFormatter(), cancellationToken);
}
public static async Task<HttpResponseMessage> PostAsJsonWithNoCharSetAsync<T>(this HttpClient client, string requestUri, T value)
{
return await client.PostAsync(requestUri, value, new NoCharSetJsonMediaTypeFormatter());
}
}
For more direct control over the payload you send, you can create derived HttpContent classes instead of letting your object be passed to an ObjectContent class which then delegates streaming to a Formatter class.
A JsonContent class that supports both reading and writing looks like this,
public class JsonContent : HttpContent
{
private readonly Stream _inboundStream;
private readonly JToken _value;
public JsonContent(JToken value)
{
_value = value;
Headers.ContentType = new MediaTypeHeaderValue("application/json");
}
public JsonContent(Stream inboundStream)
{
_inboundStream = inboundStream;
}
public async Task<JToken> ReadAsJTokenAsync()
{
return _value ?? JToken.Parse(await ReadAsStringAsync());
}
protected async override Task<Stream> CreateContentReadStreamAsync()
{
return _inboundStream;
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
if (_value != null)
{
var jw = new JsonTextWriter(new StreamWriter(stream)) {Formatting = Formatting.Indented};
_value.WriteTo(jw);
jw.Flush();
} else if (_inboundStream != null)
{
return _inboundStream.CopyToAsync(stream);
}
return Task.FromResult<object>(null);
}
protected override bool TryComputeLength(out long length)
{
length = -1;
return false;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
_inboundStream.Dispose();
}
base.Dispose(disposing);
}
}
Once you have this class you can then do,
var content = new JsonContent(myObject);
_httpClient.PostAsync(uri,content);
If you need to change any of the content Headers you can do that manually before sending the request. And if you need to mess with any of the request headers then you use the SendAsync overload,
var content = new JsonContent(myObject);
// Update Content headers here
var request = new HttpRequestMessage {RequestUri = uri, Content = content };
// Update request headers here
_httpClient.SendAsync(request);
Derived content classes are easy to create for pretty much any media type or any source of data. I've created all kinds of classes derived from HttpContent. e.g. FileContent, EmbeddedResourceContent, CSVContent, XmlContent, ImageContent, HalContent, CollectionJsonContent, HomeContent, ProblemContent.
Personally, I've found it gives me much better control over my payloads.
You can derive from JsonMediaTypeFormatter and override SetDefaultContentHeaders.
Call base.SetDefaultContentHeaders()
and then clear headers.ContentType.CharSet
then write your own extension method based on the following code:
public static Task<HttpResponseMessage> PostAsJsonAsync<T>(this HttpClient client, string requestUri, T value, CancellationToken cancellationToken)
{
return client.PostAsync(requestUri, value,
new JsonMediaTypeFormatter(), cancellationToken);
}
In essence something like:
public static Task<HttpResponseMessage> PostAsJsonWithNoCharSetAsync<T>(this HttpClient client, string requestUri, T value, CancellatioNToken cancellationToken)
{
return client.PostAsync(requestUri, value,
new NoCharSetJsonMediaTypeFormatter(), cancellationToken);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With