Setting HttpContext Response using HttpResponseMessage or Request.CreateResponse in WebApi2

Background

In my recent Continuous Improvement (CI) initiative I have been introducing few ActionFilters for the WebApi Controllers.

These action filters validates the request by using payload or the current user token against some business logics. If the request is not fulfilling business requirements then the filter should stop further processing and send response (ActionContext.Response) back from the filter pipeline.

In my projects, as of now, the default response content type is JSON.

HttpContent – ObjectContent or StringContent

The .NET Framework provides a few built-in implementations of HttpContent, here are some of the most commonly used:

  • ByteArrayContent: represents in-memory raw binary content
  • StringContent: represents text in a specific encoding (this is a specialisation of ByteArrayContent)
  • StreamContent: represents raw binary content in the form of a Stream.
  • ObjectContent is the generic implementation of the <T> type.

Problem

My basic requirement is to send JSON and I got stuck into the argument of using different objects that .net framework provides. Because my response type JSON, which is string, I can use StringContent StreamContent or even ObjectContent. The problem, what is the difference and what is the best approach in using different HttpContent sub classes.

Lets dig into each type one by one.

StringContent

StringContent is the subclass of ByteArrayContent, which is inheriting from further inheriting from HttpContent.

If I use StringContent then in that case I will have to tell lots of things when building an object such as setting content type, character set etc.. .

var errorResponse = new ResponseBase {
     Messages = new List { new Message {
             Type = MessageTypes.Error,
             Code = ErrorCode ,
             Description = ErrorMessage 
            } }
};

var response = new HttpResponseMessage {
 StatusCode = System.Net.HttpStatusCode.OK,
 Content = new StringContent(
 Newtonsoft.Json.JsonConvert.SerializeObject(errorResponse), System.Text.Encoding.UTF8, 
"application/json"),
 };

actionContext.Response = response;

I am setting the encoding as well the content type manually. Thus, what if the client negotiate the content type as XML ?

ByteArrayContent is definitely a good candidate when you have your data in the byte format such as Picture Content from the server.

ObjectContent

I can use ObjectContent class type, which is inherited from HttpContent. I can even pass a formatter object. However, it is not that easy to use because I need to pass the object type and it cannot take the formatter automatically. Again, there is a lot of hard coded settings that I need to pass to the ObjectContent.

var response = new HttpResponseMessage(HttpStatusCode.OK)
 {
 Content = new ObjectContent(typeof(ResponseBase),
 myobject,
 GlobalConfiguration.Configuration.Formatters.JsonFormatter)
 };

actionContext.Response = response;

The another most important factor of not using StringContent, ByteArrayContent, or ObjectContent directly with HttpResponseMessage is it does not recognise any serialisation configuration such as Camel case settings. Thus, either you have to pass it if it accept or do manual manipulations.

So what should be used then?

Well… the Winner is…Request.CreateResponse extension method.

Even though I have not mentioned this but the winner is somebody else. If you are using WebApi 2, like I am, it has introduced a method against Http request message object that instead of creating HttpResponse object and assigning to the response, we could just set the actionContext.Request.CreateResponse(…) extension method.

actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, 
modelState.ValidationErrors(ErrorCode));

Benefits

  • It is neat and clean. I don’t have to create an HttpResponse object and set contents separately.
  • Based on the current HttpConfiguration and Content-Type passed in Request header, the CreateResponse extension negotiate the Formatter that it will from the HttpConfiguration.Formatters list. It means that I don’t have to specify any Serialization Configuration.
  • If the configuration has been modified, for example, in case of JSON Camel case then it pick up automatically with no special check from our side.
  •  It will look after for everything by default. Otherwise we have to do allot manually. Thus it has removed some potential bugs as well.
What is the value of actionContext.Response.Content.Headers.ContentType if you use 
Request.CreateResponse method?

By using CreateResponse it automatically checks the content type, from the request, and use 
that specific formatter. Otherwise, If there is no content-type in the request, then the 
default is based on which one is first in the list of HttpConfiguration.Formatters.

In case of StringContent, we'd to hard code the content type so even if the client is
negotiating for XML content types, it will send JSON. which is wrong.