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.