Implement Version in Web API: Using Different Controller

Version implementation in any service based application is very crucial. There are many reasons for new versions of software applications. Sometimes bugs are fixed and sometimes the service needs improvement depending on the client’s demands.

But after releasing a new version we should not stop the old version or service (Ha..Ha… If it is stopped, then there may be thousands of mail overflowing the support mailbox). So, the primary concept of a service based application (not only service, but any application), once it has been released, is that we cannot change anything in the released application. If necessary we need to implement the updated version and let users consume the updated and backdated version both.

The real example is the versions of the jQuery library. When a new version becomes available, CDN does not stop hosting the backdated one.

Fine, we have the fundamental idea behind versions, in this article we will learn to implement a version in a Web API application. There are the following three ways to implement versions in Web API applications:

  1. By adding new Controller
  2. By sending Query string
  3. By request header

And since it’s not possible to represent all of them in a single article, I have decided to represent them in three different articles. In this article, we will learn to implement multiple version of an existing application by adding a new controller class.

Before getting to the implementation, the truth must be told. This is not the best idea to implement versioning. We will explain the limitations at the end of the article.

Let’s create a student information service with two versions. In the first version we will disclose the student name and surname along with her ID. But in the second version we will expose a little more data from the service. By consuming the second version we can get student’s course information.

That is quite simple to implement, let’s go step-by-step.

1. Implement Model class

There is nothing special here. We have implemented a StudentInformation Model class with two constructors. The two constructors will help to create an object of the StudentInformation class from a LINQ query. That we will see shortly.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestWEB_API.Models
{
    [Serializable]
    public class StudentInformation
    {
        public int Id;
        public string Name;
        public string Surname;
        public string Course;
        public StudentInformation(int Id, string Name, string Surname)
        {
            this.Id = Id;
            this.Name = Name;
            this.Surname = Surname;
        }
        public StudentInformation(int Id, string Name, string Surname, String Course)
        {
            this.Id = Id;
            this.Name = Name;
            this.Surname = Surname;
            this.Course = Course;
        } 
    }
}

The Serializable attribute was used to keep persistence of the Model object at the time of the request and response. Fine, nothing more in the Model implementation.

Step 2: Implement StudentV1 controller

As we said, we will a implement version with a different controller class. This is the first version of Student Information service application. We are populating some static data and returning a few information (except course) by querying a List using LINQ with a specific student ID.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using TestWEB_API.Models;
namespace TestWEB_API.Controllers
{
    public class StudentV1Controller : ApiController
    {
        List<StudentInformation> SInfo = new List<StudentInformation>();
        StudentV1Controller()
        {
            SInfo.Add(new StudentInformation(1,"Sourav","Kayal","MCA"));
            SInfo.Add(new StudentInformation(2, "Ram", "Kumar", "B.Sc"));
            SInfo.Add(new StudentInformation(3, "Manish", "Khanra", "B.Tech"));
        }
        public IEnumerable<StudentInformation> Get(int ID)
        {
            var stud = from m in SInfo.Where(s => s.Id == ID)
                       select new StudentInformation(
                           m.Id,
                           m.Name,
                           m.Surname
                       );
            return  stud;
        }
    }
}

Step 3: Implement StudentV2 controller

This is another version of the controller in the Student Information service application. We have named it StudentV2. In this version we are exposing a little more information about the student. The implementation is very similar to the first version except there is a little change in the LINQ query.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using TestWEB_API.Models;
namespace TestWEB_API.Controllers
{
    public class StudentV2Controller : ApiController
    {
        List<StudentInformation> SInfo = new List<StudentInformation>();
        StudentV2Controller()
        {
            SInfo.Add(new StudentInformation(1,"Sourav","Kayal","MCA"));
            SInfo.Add(new StudentInformation(2, "Ram", "Kumar", "B.Sc"));
            SInfo.Add(new StudentInformation(3, "Manish", "Khanra", "B.Tech"));
        }
        public IEnumerable<StudentInformation> Get(int ID)
        {
            var stud = from m in SInfo.Where(s => s.Id == ID)
                       select new StudentInformation(
                           m.Id,
                           m.Name,
                           m.Surname,
                           m.Course
                       );
            return  stud;
        }
    }
}

Step 4: Implement routing for both controllers

This is the most important and key point of this implementation. We are redirecting and pointing to HTTP traffic towards the right controller by specifying a different routing for both of them. This is my WebApiConfig.cs file. If we closely look at both routings then we will find that we have specified a different default controller in both routing information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace TestWEB_API
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "StudentV1",
                routeTemplate: "api/Student/V1/{id}",
                defaults: new { controller = "StudentV1" }
            );
            config.Routes.MapHttpRoute(
                name: "StudentV2",
                routeTemplate: "api/Student/V2/{id}",
                defaults: new { controller = "StudentV2"}
            );
        }
    }
}

Now if we want to access the student information using the V1 service application then we need to specify the URL using the following.

Implement routing

Here the version 1 is executing and we are not getting course information from the service application. Now, the updated version is given below.

updated version

Cheers!! we are getting all the information about students. It’s working fine but the great problems are:

  • We are changing the URL when we are launching a new version of the same application. It is against the REST principal.
  • We are adding a new controller for each new version, again that is a bad design pattern.

Mainly there are two issues in this implementation (as far as I know). In the next type of implementation we will try to solve those limitations.

What have we learned?

Nothing ! .If the trick is already familiar to you. (Ha..Ha..) If not, then we have learned to implement versioning in a Web API application using a different controller technique. Happy day. Keep learning.


Similar Articles