How to change WebApi Content Negotation with a simple attribute

2012-10-01

Today I was working on integrating with some third party software. I needed to create a web service that should return some XML to the third party application.

Content Negotation is a really nice feature in WebAPI. If you request JSON, you get JSON. If you request XML, you will get XML. The only problem was that they where specifying an incorrect header in the request. Because of this WebApi didn’t return XML and the third party application threw an exception.

Filing a bug would take to long so I started checking if I could somehow force the output of my WebApi to XML. After digging trough the WebApi source code (http://aspnetwebstack.codeplex.com/) I build a working solution that only requires you to use a single attribute.

XmlOutputAttribute

The following attribute can be applied to an Action Method. It will then force the output to XML.

public class XmlOutputAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        ObjectContent content = actionExecutedContext.Response.Content as ObjectContent;
        var value = content.Value;
        Type targetType = actionExecutedContext.Response.Content.GetType().GetGenericArguments()\[0\];

        var httpResponseMessage = new HttpResponseMessage
        {
            StatusCode = HttpStatusCode.OK,
            RequestMessage = actionExecutedContext.Request,
            Content = new ObjectContent(targetType, value, new XmlMediaTypeFormatter(), (string)null)
        };

        actionExecutedContext.Response = httpResponseMessage;
        base.OnActionExecuted(actionExecutedContext);
   }
}

How it works

The HttpActionExecutedContext has a Response property that contains all data WebAPI uses to create a Response for the client.

A HttpResponseMessage has three properties that are important to us:

  • StatusCode
  • RequestMessage
  • Content

When creating the new XML HttpResponseMessage I give it a default status code of OK and reuse the Request from the HttpActionExecutedContext.

The Content is the property we want to change. We need to create a new ObjectContent and use that in the HttpResponseMessage.

The constructor looks like this:

public ObjectContent(Type type, object value, MediaTypeFormatter formatter, string mediaType);

We can get the type of the return data from the original Response.ObjectContent. For the formatter we use the XmlMediaTypeFormatter and a null for mediaType.

That’s it! Then we have our new ResponseMessage and we can set it as the new value on our HttpActionExecutedContext.

ASP.NET MVC and ASP.NET WebApi both have a really great design. It’s easy to extend and you can do almost anything you can imagine.

I’m not sure this is the best way to do it but it works! If you have a better solution to this problem or if you have you created similar code then please leave a comment!