Supporting only JSON in ASP.NET Web API – the right way

Β· 573 words Β· 3 minutes to read

Sometimes (or perhaps, quite often?) you only need to support JSON in your ASP.NET Web API. In these cases, the ability of Web API pipeline to facilitate various media types is of no value for you - and you probably do not care at all about content negotiation.

In such situations it is often suggested to remove other media type formatters and only leave JsonMediaTypeFormatter. In fact, the author of this blog has earned almost 20 StackOverflow points for this type of suggestion.

However, there is even better way to solve this problem, and you’ll love it if you are into micro-optimizations.

JSON in Web API - the formatter based approach πŸ”—

As mentioned in the introduction, the most common approach to support JSON only is to clear other formatters and leave only JsonMediaTypeFormatter around.

Given an instance of HttpConfiguration you’d simply clear all and re-add JsonMediaTypeFormatter:

configuration.Formatters.Clear();  
configuration.Formatters.Add(new JsonMediaTypeFormatter());  

However, the caveat here is that even though we cleared all other formatters; the entire content negotiation process is still happening - which is a tiny overhead, you shouldn’t really have to pay for. Because we do know the outcome already, so why waste any cycles at all with conneg?

Enter approach number 2 - customizing content negotiation - which happens to be better suited for this task.

JSON in Web API - the conneg based approach πŸ”—

The better way to achieve this goal is to replace the default Web API’s content negotiation mechanism (or, in short, conneg), with a custom one that doesn’t do anything except yields JSON result straight away.

The extensibility interface for conneg is IContentNegotiator, and it’s Negotiate method. It’s role is to take the Type definition, request and the collection of formatters - all these products will participate in the conneg process.

Based on those “ingredients”, it then returns a ContentNegotiationResult which is a wrapper object around the outcome of the negotiation - the selected headers and the selected formatter.

Following the feedback from Youssef Moussaoui from ASP.NET team, I have changed the original approach a bit. In this specific scenario, we will pass in an instance of JsonMediaTypeFormatter into a customized conneg negotiator to always return the content type of application/json and the predefined formatter - JsonMediaTypeFormatter. This way we avoid re-creating the formatter per every request, and also we allow the user to pass in custom serializer settings.

public class JsonContentNegotiator : IContentNegotiator  
{  
private readonly JsonMediaTypeFormatter _jsonFormatter;

public JsonContentNegotiator(JsonMediaTypeFormatter formatter)  
{  
_jsonFormatter = formatter;  
}

public ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters)  
{  
var result = new ContentNegotiationResult(_jsonFormatter, new MediaTypeHeaderValue("application/json"));  
return result;  
}  
}  

Now all that’s left to do is to register the new mechanism against your instance of the HttpConfiguration:

var jsonFormatter = new JsonMediaTypeFormatter();  
//optional: set serializer settings here  
config.Services.Replace(typeof(IContentNegotiator), new JsonContentNegotiator(jsonFormatter));  

So now, instead of relying on DefaultContentNegotiator, which does a lot of things in its Negotiate implementation, we plugged in a custom one that only supports JSON and immediately returns that.

On a side note, you may wish to revisit my post about Content Negotiation to understand better what each of these steps does and how to customize it. Bottom line here is, that with this custom IContentNegotiator you have, in an elegant and performance friendly way got rid of all content negotiation in your application and directed everything towards being JSON based only.

Naturally, if you now run your application, every single request will use only your new IContentNegotiator.

About


Hi! I'm Filip W., a cloud architect from ZΓΌrich πŸ‡¨πŸ‡­. I like Toronto Maple Leafs πŸ‡¨πŸ‡¦, Rancid and quantum computing. Oh, and I love the Lowlands 🏴󠁧󠁒󠁳󠁣󠁴󠁿.

You can find me on Github, on Mastodon and on Bluesky.

My Introduction to Quantum Computing with Q# and QDK book
Microsoft MVP