In order to successfully iterate the upgrade, the Web API in the maintenance process is constantly upgraded, but users can not force them to follow you every time to upgrade, which will let users patience. In order to ensure that different versions of the client can be compatible, it is necessary to add version control to the Web API interface.
Of course, versioning is also good for the code we develop, not to get into chaos. The version parameter can be placed in the requested URL as part of the routing parameter, or it can be placed in the header. The solution is to implement ihttpcontrollerselector and replace it in the Webapiconfig registration method.
Public classVersionhttpcontrollerselector:ihttpcontrollerselector {Private Const stringVersionkey ="version"; Private Const stringControllerkey ="Controller"; Private ReadOnlyhttpconfiguration _configuration; Private ReadOnlylazy<dictionary<string, httpcontrollerdescriptor>>_controllers; Private ReadOnlyhashset<string>_duplicates; Publicversionhttpcontrollerselector (httpconfiguration config) {_configuration=config; _duplicates=Newhashset<string>(stringcomparer.ordinalignorecase); _controllers=Newlazy<dictionary<string, httpcontrollerdescriptor>>(initializecontrollerdictionary); } Privatedictionary<string, httpcontrollerdescriptor>initializecontrollerdictionary () {varDictionary =Newdictionary<string, httpcontrollerdescriptor>(stringcomparer.ordinalignorecase); Iassembliesresolver Assembliesresolver=_configuration. Services.getassembliesresolver (); Ihttpcontrollertyperesolver Controllersresolver=_configuration. Services.gethttpcontrollertyperesolver (); ICollection<Type> controllertypes =controllersresolver.getcontrollertypes (Assembliesresolver); foreach(Type tinchcontrollertypes) { varsegments =T.namespace.split (Type.delimiter); varControllername = T.name.remove (T.name.length-DefaultHttpControllerSelector.ControllerSuffix.Length); stringVersion = Segments[segments. Length-1]; varKey = String.Format (CultureInfo.InvariantCulture,"{0}. {1}", version, controllername); if(Version = ="Controllers") {Key= String.Format (CultureInfo.InvariantCulture,"{0}", controllername); } //Check for duplicate keys. if(dictionary. Keys.contains (key)) {_duplicates. ADD (key); } Else{Dictionary[key]=NewHttpcontrollerdescriptor (_configuration, T.name, T); } } foreach(stringSinch_duplicates) {Dictionary. Remove (s); } returndictionary; } //Get A value from the route data, if present. Private StaticT getroutevariable<t> (Ihttproutedata routedata,stringname) { Objectresult =NULL; if(RouteData.Values.TryGetValue (Name, outresult)) { return(T) result; } return default(T); } Publichttpcontrollerdescriptor Selectcontroller (httprequestmessage request) {Ihttproutedata Routedata
=request. Getroutedata (); if(Routedata = =NULL) { Throw Newhttpresponseexception (Httpstatuscode.notfound); } //Get the version and controller variables from the route data. stringVersion = getroutevariable<string>(Routedata, Versionkey); if(string. IsNullOrEmpty (Version)) {version=Getversionfromhttpheaderandacceptheader (Request); } stringControllername = getroutevariable<string>(Routedata, Controllerkey); if(Controllername = =NULL) { Throw Newhttpresponseexception (Httpstatuscode.notfound); } //Find a matching controller. stringKey = String.Format (CultureInfo.InvariantCulture,"{0}", controllername); if(!string. IsNullOrEmpty (version)) {Key= String.Format (CultureInfo.InvariantCulture,"{0}. {1}", version, controllername); } Httpcontrollerdescriptor Controllerdescriptor; if(_controllers. Value.trygetvalue (Key, outcontrollerdescriptor)) { returnControllerdescriptor; } Else if(_duplicates. Contains (key)) {Throw Newhttpresponseexception (Request. Createerrorresponse (Httpstatuscode.internalservererror,"multiple controllers were found the match this request.")); } Else { Throw Newhttpresponseexception (Httpstatuscode.notfound); } } Publicidictionary<string, httpcontrollerdescriptor>getcontrollermapping () {return_controllers. Value; } Private stringGetversionfromhttpheaderandacceptheader (Httprequestmessage request) {if(Request. Headers.contains (Versionkey)) {varVersionheader =request. Headers.getvalues (Versionkey). FirstOrDefault (); if(Versionheader! =NULL) { returnVersionheader; } } varAcceptHeader =request. headers.accept; foreach(varMimeinchAcceptHeader) { if(MIME. mediatype = ="Application/json"|| Mime. mediatype = ="text/html") { varVersion =MIME. Parameters. Where (v=v.name.equals (Versionkey, StringComparison.OrdinalIgnoreCase)). FirstOrDefault (); if(Version! =NULL) { returnversion. Value; } return string. Empty; } } return string. Empty; } }
View Code
The focus is on the Selectcontroller method to find the appropriate version of the controller from the HTTP request. I'm here to get the version from the routing and header, get it from the route first, and not get it from the header.
Ihttproutedata Routedata =request. Getroutedata (); if(Routedata = =NULL) { Throw Newhttpresponseexception (Httpstatuscode.notfound); } //Get the version and controller variables from the route data. stringVersion = getroutevariable<string>(Routedata, Versionkey); if(string. IsNullOrEmpty (Version)) {version=Getversionfromhttpheaderandacceptheader (Request); }
Private stringGetversionfromhttpheaderandacceptheader (Httprequestmessage request) {if(Request. Headers.contains (Versionkey)) {varVersionheader =request. Headers.getvalues (Versionkey). FirstOrDefault (); if(Versionheader! =NULL) { returnVersionheader; } } varAcceptHeader =request. headers.accept; foreach(varMimeinchAcceptHeader) { if(MIME. mediatype = ="Application/json"|| Mime. mediatype = ="text/html") { varVersion =MIME. Parameters. Where (v=v.name.equals (Versionkey, StringComparison.OrdinalIgnoreCase)). FirstOrDefault (); if(Version! =NULL) { returnversion. Value; } return string. Empty; } } return string. Empty; }
The Webapiconfig file call code is as follows:
Public Static void Register (httpconfiguration config) {。。。 Config. Services.replace (typeofnew versionhttpcontrollerselector (config));}
The definition of the Web API, it is possible to differentiate from the namespace. For example, the Loginapicontroller namespace with version number V1 is defined as XXX. WebAPI.Controllers.V1, the namespace for the Loginapicontroller with version number V2 is defined as XXX. WebAPI.Controllers.V2, and so on,
The client adds parameter versoin=v1/v2 to the header ... You can specify that you use different versions of the API.
E-Commerce System Architecture Summary 4 (WEBAPI version control)