How to do versioning with the Querystring parameter in C# ASP.NET WebAPI?

Querystring parameter versioning in ASP.NET Web API allows different API versions to be accessed using a query parameter like ?v=1 or ?v=2. By default, the DefaultHttpControllerSelector cannot route to version-specific controllers, so we need to create a custom controller selector.

This approach enables you to maintain multiple API versions simultaneously while using descriptive controller names like StudentsV1Controller and StudentsV2Controller.

How It Works

The default controller selection process looks for a controller named exactly as specified in the route (e.g., StudentsController). When you have version-specific controllers like StudentsV1Controller, the default selector fails and returns a 404 error.

Controller Selection Process Request: /api/student?v=1 CustomControllerSelector StudentV1Controller Query: v=1 Parses version Appends "V1" Returns data Default selector would look for "StudentController" and fail

Creating a Custom Controller Selector

The custom controller selector inherits from DefaultHttpControllerSelector and overrides the SelectController method to parse the version parameter and route to the appropriate versioned controller −

using System.Net.Http;
using System.Web;
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";
            
            var versionQueryString = HttpUtility.ParseQueryString(request.RequestUri.Query);
            if (versionQueryString["v"] != null)
            {
                versionNumber = versionQueryString["v"];
            }
            
            if (versionNumber == "1")
            {
                controllerName = controllerName + "V1";
            }
            else if (versionNumber == "2")
            {
                controllerName = controllerName + "V2";
            }
            
            HttpControllerDescriptor controllerDescriptor;
            if (controllers.TryGetValue(controllerName, out controllerDescriptor))
            {
                return controllerDescriptor;
            }
            
            return null;
        }
    }
}

Registering the Custom Controller Selector

Replace the default IHttpControllerSelector with your custom implementation in WebApiConfig.cs

using System.Web.Http;
using WebAPI.Custom;

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-Specific Controllers

StudentV1Controller

using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

public class StudentV1
{
    public int Id { get; set; }
    public string Name { get; set; }
}

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)
    {
        return students.FirstOrDefault(x => x.Id == id);
    }
}

StudentV2Controller

using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

public class StudentV2
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

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)
    {
        return students.FirstOrDefault(x => x.Id == id);
    }
}

Usage Examples

Once configured, you can access different API versions using query parameters −

GET /api/student?v=1    // Returns StudentV1 data format
GET /api/student?v=2    // Returns StudentV2 data format
GET /api/student/1?v=1  // Returns specific student in V1 format
GET /api/student/1?v=2  // Returns specific student in V2 format

The responses will have different structures based on the version −

Version 1 Response:
[{"Id": 1, "Name": "Mark"}, {"Id": 2, "Name": "John"}]

Version 2 Response:  
[{"Id": 1, "FirstName": "Roger", "LastName": "Federer"}, 
 {"Id": 2, "FirstName": "Tom", "LastName": "Bruce"}]

Conclusion

Querystring parameter versioning in ASP.NET Web API provides a flexible way to maintain multiple API versions. By implementing a custom controller selector, you can route requests to version-specific controllers based on the v parameter, allowing seamless API evolution while maintaining backward compatibility.

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

528 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements