Series Navigation Address http://www.cnblogs.com/fzrain/p/3490137.html
Once the API is released, the consumer will start to use it and mix it with other data. However, changes are inevitable when new requirements arise. You may be glad that the API changes have not been affected on the existing client, but this situation will not happen all the time.
Therefore, it is necessary to carefully consider the Version Policy of ASP. NET Web Api before implementation. In our case, the requirements have changed and we have created different versions of APIs to solve the changes without affecting the clients that are already using the APIs. We return the new API version and the old API version to the client, so that it has enough time to migrate to the latest API version. Sometimes it is possible that multiple versions coexist.
There are many ways to implement version control. This article mainly introduces URI, query string, custom Header, and receive Header.
For simplicity, let's change the Get method in "StudentsController"-in the Response Message body, we use the "CoursesDuration" and "FullName" attributes to replace the original "FirstName" and "LastName" attributes.
The simplest way is to create a Controller that is the same as "StudentsController" and name it "StudentsV2Controller ", we will select the appropriate Controller based on different API versions. In the new Controller, we implement the above changes and use the same Http method without any introduction.
The Get method of our request for "StudentsController" is that the following data is returned:
: : : : : : : : : : : :
We look forward to accessing the Get method of "StudentsV2Controller", which should be:
: : : : : : : : : : : :
OK. copy and paste "StudnetsController" and rename it "StudnetsV2Controller" to change the Get method:
IEnumerable<StudentV2BaseModel> Get( page = , pageSize = <Student>= TheRepository.GetAllStudentsWithEnrollments().OrderBy(c => totalCount = totalPages = Math.Ceiling(()totalCount / urlHelper = prevLink = page > ? urlHelper.Link(, { page = page - , pageSize = pageSize }) : nextLink = page < totalPages - ? urlHelper.Link(, { page = page + , pageSize = pageSize }) : paginationHeader = ==== results =*=>
We can see that there are few changes here, and the returned type is changed to "StudentV2BaseModel", which is created by the CreateV2Summary method of ModelFactory. Therefore, we need to add the StudentV2BaseModel class and the CreateV2Summary method:
Id { ; Url { ; FullName { ; Data.Enums.Gender Gender { ; EnrollmentsCount { ; CoursesDuration { ; = _UrlHelper.Link(, { userName === .Format(=== Math.Round(student.Enrollments.Sum(c =>
So far, our preparations have been completed. The following describes four methods to implement version changes.
It is the most common practice to include a version number in a URI. If you want to use an api of version V1 (using http: // localhost: {your_port}/api/v1/students/), likewise, if you want to use the V2 api (Use http: // localhost: {your_port}/api/v2/students /)
The advantage of this method is that the client knows which version of the api is used, and the implementation method is to add two routes in "WebApiConfig:
{ controller = , userName = { controller = , userName =
In the above Code, we added two routing rules, which correspond to each other's controllers. If we plan to add V3 in the future, we need to add another one. This will become more and more chaotic.
The main disadvantage of this technology is that it does not conform to the REST specifications because the URI changes constantly. In other words, once we release a new version, we have to add a new route.
Before explaining the other three implementation modes, let's take a look at how the web api framework selects the corresponding Controller based on our requests: there is a "DefaultHttpControllerSelector" Class in the web api. There is a method "SelectController ()", which receives a parameter of the "HttpRequestMessage" type. This object contains a route data containing key/value pairs, including the controller name configured in "WebApiConfig. According to this information, obtain all classes implementing "ApiController" through reflection, and the web api will match this Controller. If the matching result is not equal to 1 (equal to 0 or greater than or equal to 2 ), then an exception is thrown.
We define a class "LearningControllerSelector" to inherit from "Http. Dispatcher. DefaultHttpControllerSelector" and override the "SelectController ()" method. The specific code is as follows:
= controllers = GetControllerMapping(); routeData = controllerName = routeData.Values[ (controllers.TryGetValue(controllerName, version = versionedControllerName = .Concat(controllerName, (controllers.TryGetValue(versionedControllerName,
The above code mainly refers to the following:
1. Call the parent class method GetControllerMapping () to obtain all classes that implement ApiController.
2. Get routeData through the request object, and then obtain the Controller name.
3. Create an "HttpControllerDescriptor" Object Based on the Controller we just obtained. This object contains information about the Controller.
4. Next, add "V" and the version number after the Controller name we found. Repeat the preceding steps. For how to obtain the version number, we will discuss it later. It will be "2" for the time being ".
To make the custom "Controller Selector" take effect, you need to make the following configuration in "WebApiConfig:
config.Services.Replace((IHttpControllerSelector), LearningControllerSelector((config)));
Next we will implement how to send the version number of the request.
If you use query string to set the version, add "? V = 2 ", for example, this URI: http: // localhost: {your_port}/api/students /? V = 2
We can think that the client does not provide the query string version number, so the default version number is "1 ".
The implementation is not complex. In our "LearningControllerSelector" class, add a "GetVersionFromQueryString ()" method, which receives an HttpRequestMessage parameter, obtain the version required by the client from the request object:
query = version = query[ (version !=
We only need to call this method in the SelectController method. The only drawback is that the URI changes and does not comply with the REST specifications.
Now we use another method to generate a Version number-a custom request header, which is not part of the URI. Add the header "X-Learning-Version" and set the Version number in it, when the client does not have this header, we can think that it requires version V1.
To implement this technology, we add a "GetVersionFromHeader" method in "LearningControllerSelector". The Code is as follows:
HEADER_NAME = versionHeader = (versionHeader !=
The method here is very simple. first determine the name of the request Header, and then find it in the request Header. If there is data, you will get it.
The client sends the following request:
This method directly uses the Accept Header and sets it to "Accept: application/json; version = 2" during the request. We still think that if the client does not provide the version number, we will give the V1 data.
Add the "GetVersionFromAcceptHeaderVersion" method to the "LearningControllerSelector" class. The specific implementation is as follows:
acceptHeader = ( mime (mime.MediaType == version ==> v.Name.Equals( (version !=
This implementation looks more standard and professional than above.
Source Code address: https://github.com/fzrain/WebApi.eLearning