Use a Message Handler to Set ASP.NET Web API’s Current Thread Culture

ASP.NET Web API provides very streamlined support in the framework to handle content negotiation. In HTTP specs, following Accept series of headers are used in a HTTP client to set in the request for content:

ASP.NET Web API supports first two headers out of the box. The framework itself would select the right MediaTypeFormatter class based upon the Accept header, and a selected MediaTypeFormatter is able to handle Accept-Charset to return the result in the right character set. For example, when a HTTP client sends

The Web API framework will select JsonMediaTypeFormatter as the media type formatter for the response of this request. In turn JsonMediaTypeFormatter is able to take advantage of the backing library JSON.NET and returns the JSON serialization result in the right character set.

As stated in the link above, Accept-Language is not yet automatically supported in the framework. Web API provides several nice extension points to solve such a problem.

Checking the Pipeline

Picking an extension point of such a feature may not be the easiest thing to do. The Web API has the following extension points in the order of execution when the HTTP server receive a request:

  • Global message handlers
  • Per-route message handlers
  • Authorization filters
  • Action Filters

If we consider the importance of current thread’s Culture — when we choose to change the current thread’s culture, all subsequent calls to format dates, numbers, currencies and retrieving resources will return different results — I would like changing current thread’s culture to be as early as possible.

Here is a snapshot from the following chart:

Screenshot 2014-04-25 20.34.45

The chart shows very clearly that the earliest extension point to an incoming request is the global message handler queue. We can certainly implement a custom message handler, insert it into this queue and ask Web API to use this custom message handler to process the HTTP header first.

Implementing the Message Handler

Here is the message handler:

As stated in the HTTP protocol, Accept-Language uses quality values to note the request’s preferences of languages. The first part of code above prioritizes languages based upon quality. The second part finds an available language. The third part sets the thread culture.

Now we have the message handler ready, we can insert this message handler into the pipeline:

This should be implemented in your WebApiConfig.Register() method, and get called when the Web API application starts.

A Short Introduction of BookSleeve Redis Client

BookSleeve (project site, author blog post) provides a native async Redis client for .NET with effortless multiplex support, as an alternative to the famous ServiceStack.Redis.

In BookSleeve Redis commands are always pipelined and handled by async tasks. One single BookSleeve connection can handle numerous commands in one go. For example,

In this example,  the three commands to set three keys with a single connection are multiplexed and put into a single pipeline to execute on the Redis server. The tasks end when the commands complete.

Without pipelining, on Redis these commands are individual requests. Each request has to wait for the response to come back and they incur a round trip each time to the Redis server.

With pipelining,  these commands are grouped together as one request and sent to Redis in one go. So the network wait time is much less than the previous scenario by cutting 2/3 of the network round trip wait time.

If a separate method executes different Redis commands with the same connection simultaneously,

All the commands are then multiplexed together and executed on Redis in one of several possibilities of execution order,

In this scenario, the network wait time is cut by 4/5 of requests being sent individually, with a slight bigger request sent to the Redis server in one go.

On .NET side, since BookSleeve’s connection is always async and returns tasks, the caller can await the tasks to get the actual results, while the tasks are executed without blocking each other. Commands from different method calls and different threads can be multiplexed together and sent to Redis in one request. Above all, this approach should improve Redis performance by cutting the round trip time of individual requests with less connections to Redis.