ASP.NET Web API Custom RouteDataMapping (MediaTypeMapping)

In this post, we will create RouteDataMapping. This custom MediaTypeMapping will allow us to involve the decision-making process about the response format according to RouteData values.
2012-03-03 23:05
Tugberk Ugurlu


I have talked about on ASP.NET Web API Content-Negotiation algorithm and MediaTypeMapping on my previous post. As I said there, creating one custom MediaTypeMapping is fairly simple.

In this post, we will create RouteDataMapping. This custom MediaTypeMapping will allow us to involve the decision-making process about the response format according to RouteData values. Here is the complete implementation:

public class RouteDataMapping : MediaTypeMapping {

    private readonly string _routeDataValueName;
    private readonly string _routeDataValueValue;

    public RouteDataMapping(
        string routeDataValueName, 
        string routeDataValueValue, 
        MediaTypeHeaderValue mediaType) : base(mediaType) {

        _routeDataValueName = routeDataValueName;
        _routeDataValueValue = routeDataValueValue;
    }

    public RouteDataMapping(
        string routeDataValueName, 
        string routeDataValueValue, 
        string mediaType) : base(mediaType) {

        _routeDataValueName = routeDataValueName;
        _routeDataValueValue = routeDataValueValue;
    }

    protected override double OnTryMatchMediaType(
        System.Net.Http.HttpResponseMessage response) {

        return (
            response.RequestMessage.GetRouteData().
            Values[_routeDataValueName].ToString() == _routeDataValueValue
        ) ? 1.0 : 0.0;
    }

    //Don't use this
    //This will be removed on the first RC (according to team members)
    protected override double OnTryMatchMediaType(
        System.Net.Http.HttpRequestMessage request) {

        throw new NotImplementedException();
    }
}

The implementation is fairly simple.One thing that you might notice is that we are returning double in order to tell the framework if it is a match or not. Here is the reason why:

The returned double value is used by the conneg algorithm to find the appropriate formatter to write. Its similar to how you can set the quality value in Accept header. - Kiran Challa

Let’s try this out. we will use the same sample on my previous post but we will make a few changes. First of all, we will change our route a little to add an extension. Keep in mind that you do not need to make this an extension. It will work for every RouteData value.

GlobalConfiguration.Configuration.Routes.MapHttpRoute(
    "defaultHttpRoute",
    routeTemplate: "api/{controller}.{extension}",
    defaults: new { },
    constraints: new { extension = "json|xml" }
);

Then we will make sure that we have the following registry inside our Web.config file in order for our Urls with extensions to work.

<system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
</system.webServer>

And finally, we will hook up our RouteDataMapping to the formatters:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.
    MediaTypeMappings.Add(
        new RouteDataMapping(
            "extension", "json", "application/json"
    )
);

GlobalConfiguration.Configuration.Formatters.XmlFormatter.
    MediaTypeMappings.Add(
        new RouteDataMapping(
            "extension", "xml", "application/xml"
    )
);

Now, when you navigate to /api/cars.json, you will get the data as json. If you navigate to /api/cars.xml, you will get the result as xml as below.

routeDataMapping



Comments

Tugberk
by Tugberk on Sunday, Mar 04 2012 18:29:41 +02:00

@Radenko

Only with the route I used, no. You need to define a different route for that. Actually, my intention here was not to tell that you can have api endpoint urls with extensions, it was to show how easy is to create a custom MediaTypeMapping. For that support, you should check out built-in UriExtensionMapping.

Tags