How to do versioning with accept header in C# ASP.NET WebAPI?

CsharpServer Side ProgrammingProgramming

The Accept header tells the server in what file format the browser wants the data. These file formats are more commonly called as MIME-types. MIME stands for Multipurpose Internet Mail Extensions.

Versioning can be send in Headers like below.

Version=1 StudentsV1Controller
Version=2 StudentsV2Controller

Since we have not handled the version in accept headers, we are getting 404 not found error as we only have StudentV1 and StudentV2 controller. Let us add our own CustomControllerSelector which implements the DefaultHttpControllerSelector class.

CustomControllerSelector

Example

using System.Linq;
using System.Net.Http;
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 = "";
         var acceptHeader = request.Headers.Accept.Where(a => a.Parameters
         .Count(p => p.Name.ToLower() == "version") > 0);
         if (acceptHeader.Any()){
            versionNumber = acceptHeader.First().Parameters
            .First(p => p.Name.ToLower() == "version").Value;
         }
         HttpControllerDescriptor controllerDescriptor;
         if (versionNumber == "1"){
            controllerName = string.Concat(controllerName, "V1");
         }
         else if (versionNumber == "2"){
            controllerName = string.Concat(controllerName, "V2");
         }
         if (controllers.TryGetValue(controllerName, out controllerDescriptor)){
            return controllerDescriptor;
         }
         return null;
      }
   }
}

The next thing that we need to replace the default controller selector with our custom controller selector. This is done in WebApiConfig.cs file. Notice we are replacing IHttpControllerSelector, with our CustomControllerSelector. DefaultHttpControllerSelector implements IHttpControllerSelector, so that is the reason we are replacing IHttpControllerSelector.

Example

public static class WebApiConfig{
   public static void Register(HttpConfiguration config){
      config.Services.Replace(typeof(IHttpControllerSelector), new
      CustomControllerSelector(config));
      config.MapHttpAttributeRoutes();
      config.Routes.MapHttpRoute(
         name: "DefaultApi",
         routeTemplate: "api/{controller}/{id}",
         defaults: new { id = RouteParameter.Optional }
      );
   }
}

StudentV1Controller

Example

using DemoWebApplication.Models;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace DemoWebApplication.Controllers{
   public class StudentV1Controller : ApiController{
      List<StudentV1> students = new List<StudentV1>{
         new StudentV1{
            Id = 1,
            Name = "Mark"
         },
         new StudentV1{
            Id = 2,
            Name = "John"
         }
      };
      public IEnumerable<StudentV1> Get(){
         return students;
      }
      public StudentV1 Get(int id){
         var studentForId = students.FirstOrDefault(x => x.Id == id);
         return studentForId;
      }
   }
}

StudentV2Controller

Example

using DemoWebApplication.Models;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace DemoWebApplication.Controllers{
   public class StudentV2Controller : ApiController{
      List<StudentV2> students = new List<StudentV2>{
         new StudentV2{
            Id = 1,
            FirstName = "Roger",
            LastName = "Federer"
         },
         new StudentV2{
            Id = 2,
            FirstName = "Tom",
            LastName = "Bruce"
         }
      };
      public IEnumerable<StudentV2> Get(){
            return students;
      }
      public StudentV2 Get(int id){
         var studentForId = students.FirstOrDefault(x => x.Id == id);
         return studentForId;
      }
   }
}

Below outputs shows the results that we get from StudentV1 and StudentV2 controllers with versioning in accept headers.


raja
Published on 19-Aug-2020 16:12:36
Advertisements