HttpClient: How to Remove Charset From Content-Type Header
In this post, a .NET and C# expert demonstrates how he got around an interesting problem when setting up HTTP communication for an application.
Join the DZone community and get the full member experience.
Join For FreeI was writing a client library for one online service and faced a situation where I had to remove the charset definition from the Content-Type header. It was like the content type was an application/json or the response was a 415 "Unsupported media type." I was using the HttpClient class to communicate with the service and without any additional effort charset doesn't go away. Here is how I got the charset definition away from the Content-Type header.
Problem
My problematic code was similar to the code shown here.
var newUser = new { Id = 100, Name = "John Doe" };
var newUserJson = JsonConvert.SerializeObject(newUser);
var uri = new Uri("<address to some service>");
using (var client = new HttpClient())
using (var content = new StringContent(newUserJson, Encoding.UTF8, "application/json"))
{
var result = await client.PostAsync(uri, content);
// do something with result
}
Replacing tge StringContent constructor Encoding.UTF8
with null
doesn't change the situation. In my case, I got the following result when running my code.
The charset definition in a request content type is the show stopper. To make things more interesting I brought out all the public constructors of the StringContent
class.
public StringContent(string content);
public StringContent(string content, Encoding encoding);
public StringContent(string content, Encoding encoding, string mediaType);
We either don't specify the content type and get text/plain as default or we specify the content type with text encoding. There's no way to specify just content type.
Why Use Charset With Content Type?
I guess it comes down to SEO on performance strategies. There are online services like PageSpeed Insights and YSlow that suggest giving charsets with textual content types so then server on the other end doesn't have to spend time on guessing the correct charset. There's one benefit more —if the server knows the charset before content it starts then it doesn't have to recode content that it parsed before the charset's HTML header.
Removing the Charset From a Content-Type Header
Solution is simple - we can create StringContent with whatever encoding and then set charset to empty string.
using (var client = new HttpClient())
using (var content = new StringContent(newUserJson, Encoding.UTF8, "application/json"))
{
content.Headers.ContentType.CharSet = "";
var result = await client.PostAsync(uri, content);
// do something with result
}
This removes the charset definiton from the request content-type header. My code started to work after this change.
Subclassing StringContent
Although my code worked I wasn't happy with a solution like this as I have to remember to set the charset to an empty string in every method in which I used HttpClient
. I created new StringContentWithoutCharset
class that extended StringContent
.
public class StringContentWithoutCharset : StringContent
{
public StringContentWithoutCharset(string content) : base(content)
{
}
public StringContentWithoutCharset(string content, Encoding encoding) : base(content, encoding)
{
Headers.ContentType.CharSet = "";
}
public StringContentWithoutCharset(string content, Encoding encoding, string mediaType) : base(content, encoding, mediaType)
{
Headers.ContentType.CharSet = "";
}
public StringContentWithoutCharset(string content, string mediaType) : base(content, Encoding.UTF8, mediaType)
{
Headers.ContentType.CharSet = "";
}
}
This class adds an additional constructor that accepts string content and content type. It calls the base constructor with UTF8 charset but removes the content type charset immediately. This is how my code looks when using the StringContentWithoutCharset
class:
var newUser = new { Id = 100, Name = "John Doe" };
var newUserJson = JsonConvert.SerializeObject(newUser);
var uri = new Uri("<address to some service>");
using (var client = new HttpClient())
using (var content = new StringContentWithoutCharset(newUserJson, "application/json"))
{
var result = await client.PostAsync(uri, content);
// do something with result
}
This is the solution I am currently using.
Wrapping Up
Although I don't like to extend .NET Framework classes to add just one missing controller I didn't have much of a chance this time. Still, I'm okay with this solution as it hides the implementation of the content type charset, removing it from the client code using the class. I hope the constructor I created makes its way to .NET Framework and .NET Core one day.
Published at DZone with permission of Gunnar Peipman, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments