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

The Accept header in HTTP tells the server what file format the client wants the response data in. These formats are commonly called MIME-types (Multipurpose Internet Mail Extensions). In ASP.NET Web API, you can use the Accept header to implement API versioning by including version information as a parameter in the Accept header.

This approach allows you to maintain multiple API versions while using the same URL endpoints, routing requests to different controllers based on the version specified in the Accept header.

How Accept Header Versioning Works

When a client makes a request, it includes an Accept header with version information −

Accept: application/json; version=1  ? Routes to StudentsV1Controller
Accept: application/json; version=2  ? Routes to StudentsV2Controller

Accept Header Versioning Flow Client Request version=1 Custom Controller Selector StudentsV1 Controller Client Request version=2 Custom Controller Selector StudentsV2 Controller

Creating a Custom Controller Selector

To implement Accept header versioning, you need a custom controller selector that reads the version from the Accept header and routes to the appropriate controller −

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;
        }
    }
}

Configuring the Custom Controller Selector

Replace the default controller selector with your custom implementation in the WebApiConfig.cs file −

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 }
        );
    }
}

Version 1 Controller Implementation

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;
        }
    }
    
    public class StudentV1
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

Version 2 Controller Implementation

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;
        }
    }
    
    public class StudentV2
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}

How to Test Accept Header Versioning

Use the following Accept headers in your HTTP requests −

For Version 1: Accept: application/json; version=1
For Version 2: Accept: application/json; version=2

The same URL endpoint /api/Student will route to different controllers based on the version parameter in the Accept header, allowing you to maintain backward compatibility while introducing new API versions.

Conclusion

Accept header versioning in ASP.NET Web API provides a clean way to version APIs without changing URLs. By implementing a custom controller selector, you can route requests to different controllers based on the version specified in the Accept header, maintaining multiple API versions seamlessly.

Updated on: 2026-03-17T07:04:36+05:30

693 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements