Support us .Net Basics C# SQL ASP.NET Aarvi MVC Slides C# Programs Subscribe Download

Web API versioning using custom media types

Suggested Videos
Part 36 - Web API versioning using querystring parameter
Part 37 - Web API versioning using a custom header
Part 38 - Web API versioning using accept header

In this video we will discuss versioning a Web API Service using vendor specific media types. This is continuation to Part 38. Please watch Part 38 from Web API tutorial before proceeding.



So here is what we want to be able to do. Instead of using the standard media types like application/xml or application/json, we want to use our custom media type as shown below in fillder
web api versioning media types



Notice in the media type, we have the version of the service we want. Custom media types have vnd prefix. vnd indicates that it is a vendor specific media type. So from our CustomControllerSelector class we want to read the version number from the custom media type we have specified.

The changes that are required are commented, so it is self-explanatory.

using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Dispatcher;

namespace WebAPI.Custom
{
    public class CustomControllerSelector : DefaultHttpControllerSelector
    {
        private HttpConfiguration _config;

        public CustomControllerSelector(HttpConfiguration config) : base(config)
        {
            _config = config;
        }

        public override HttpControllerDescriptor
            SelectController(HttpRequestMessage request)
        {
            var controllers = GetControllerMapping();
            var routeData = request.GetRouteData();

            var controllerName = routeData.Values["controller"].ToString();

            string versionNumber = "1";

            // Comment the code that gets the version number from Query String
            // var versionQueryString =
            //         HttpUtility.ParseQueryString(request.RequestUri.Query);
            //if (versionQueryString["v"] != null)
            //{
            //    versionNumber = versionQueryString["v"];
            //}

            // Get the version number from Custom version header

            //string customHeader = "X-StudentService-Version";
            //if (request.Headers.Contains(customHeader))
            //{
            //    // If X-StudentService-Version:1 is specified twice in the request
            //    // then in versionNumber variable will get a value of "1,1"
            //    versionNumber = request.Headers.GetValues(customHeader).FirstOrDefault();
            //    // Check if versionNumber string contains a comma, and take only
            //    // the first number from the comma separated list of version numbers
            //    if (versionNumber.Contains(","))
            //    {
            //        versionNumber = versionNumber.Substring(0, versionNumber.IndexOf(","));
            //    }
            //}

            // Get the version number from the Accept header

            // Users can include multiple Accept headers in the request
            // Check if any of the Accept headers has a parameter with name version
            //var acceptHeader = request.Headers.Accept.Where(a => a.Parameters
            //                    .Count(p => p.Name.ToLower() == "version") > 0);

            //// If there is atleast one header with a "version" parameter
            //if (acceptHeader.Any())
            //{
            //    // Get the version parameter value from the Accept header
            //    versionNumber = acceptHeader.First().Parameters
            //                    .First(p => p.Name.ToLower() == "version").Value;
            //}

            // Get the version number from the Custom media type

            // Use regular expression for mataching the pattern of the media
            // type. We have given a name for the matched group that contains
            // the version number. This enables us to retrieve the version number 
            // using the group name("version") instead of ZERO based index
            string regex =
                @"application\/vnd\.pragimtech\.([a-z]+)\.v(?<version>[0-9]+)\+([a-z]+)";

            // Users can include multiple Accept headers in the request.
            // Check if any of the Accept headers has our custom media type by
            // checking if there is a match with regular expression specified
            var acceptHeader = request.Headers.Accept
                .Where(a => Regex.IsMatch(a.MediaType, regex, RegexOptions.IgnoreCase));
            // If there is atleast one Accept header with our custom media type
            if (acceptHeader.Any())
            {
                // Retrieve the first custom media type
                var match = Regex.Match(acceptHeader.First().MediaType,
                    regex, RegexOptions.IgnoreCase);
                // From the version group, get the version number
                versionNumber = match.Groups["version"].Value;
            }

            HttpControllerDescriptor controllerDescriptor;
            if (versionNumber == "1")
            {
                controllerName = string.Concat(controllerName, "V1");
            }
            else
            {
                controllerName = string.Concat(controllerName, "V2");
            }

            if (controllers.TryGetValue(controllerName, out controllerDescriptor))
            {
                return controllerDescriptor;
            }

            return null;
        }
    }
}

So at this point, if we issue a request using our custom media type from fiddler, we get version 1 of student objects in JSON format. If you specify version 2 (v2) instead of version 1 (v1), we get version 2 student objects as expected.
web api versioning media types

Response from the web api service
web api versioning vendor specific media types

However, if we specify that we want xml format instead of json in the request as shown below. We still get JSON formatted result instead of XML formatted result. 
web api versioning custom media type example

Response from the web api service
web api versioning vendor specific media types

This is because we have not added our custome media types to the respective media type formatters (JsonFormatter and XmlFormatter). 

To add the custom media types to the JsonFormatter, include the following 2 lines of code in WebApiConfig.cs file

config.Formatters.JsonFormatter.SupportedMediaTypes
    .Add(new MediaTypeHeaderValue("application/vnd.pragimtech.students.v1+json"));
config.Formatters.JsonFormatter.SupportedMediaTypes
    .Add(new MediaTypeHeaderValue("application/vnd.pragimtech.students.v2+json"));

To add the custom media types to the XmlFormatter, include the following 2 lines of code in WebApiConfig.cs file

config.Formatters.XmlFormatter.SupportedMediaTypes
    .Add(new MediaTypeHeaderValue("application/vnd.pragimtech.students.v1+xml"));
config.Formatters.XmlFormatter.SupportedMediaTypes
    .Add(new MediaTypeHeaderValue("application/vnd.pragimtech.students.v2+xml"));

So at this point, let's issue another request using our custom media type from fiddler
web api versioning custom media type example

Notice we get version 1 of student objects in XML format as expected
web api versioning custom media type xml formatted data

ASP.NET Web API tutorial for beginners

1 comment:

  1. What is the difference between Aps web services,web API, and wcf? when use one over the other? Please explain in a video.

    ReplyDelete

It would be great if you can help share these free resources