ASP.NET Web APIでバージョンを実装するいくつかの方法
11316 ワード
ASP.NET Web APIでは、私たちのAPIが変更されると、バージョンの問題に関連します.APIのバージョンはどのように実現しますか?
1、ルーティングによるバージョン設定
最も簡単な方法は、ルーティング設定、異なるルーティング、異なるバージョン、異なるcontrollerを通じてです.
config.Routes.MapHttpRoute(
name: "Food",
routeTemplate: "api/v1/nutrition/foods/{foodid}",
defaults:...
)
config.Routes.MapHttpRoute(
name: "Foodv2",
routeTemplate: "api/v2/nutrition/foods/{foodid}",
defaults:...
)
2、HttpControllerSelector経由
HttpControllerSelectorを変更することでも実現できます.
まず、DefaultHttpControllerSelectorを継承するクラスを書きます.
using System.Web.http.Dispatcher
public class CountingKsControllerSelector : DefaultHttpControllerSelector
{
private HttpConfiguraion _config;
public CountgKsControllerSelector(HttpConfiguraiton cofig) : base(config)
{
_config = config;
}
// HttpControllerDesriptor
public override System.Web.Http.Controllers.HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
// controller
var controllers = GetControllerMapping();
//
var routeData = request.GetRouteData();
// controller
var controllerName = (string)routeData.Values["controller"];
HttpControllerDescriptor descriptor;
if(controllers.TryGetValue(controllerName, out descriptor))
{
var version = "2";
// QueryString
var newName = string.Concat(controllerName, "V", version);
HttpControllerDescriptor versionedDescriptor;
if(controllers.TryGetValue(newName, out versionedDescriptor))
{
return versionedDescriptor;
}
return descriptor;
}
return null;
}
}
WebApiConfig.csカスタムControllerSelectorの登録
config.Services.Replace(typeof(IHttpControllerSelector), new CountingKsControllerSelector(config) );
以上が大まかな実現構想である.具体的には以下のような方法で実現できる.
■Query Stringによるバージョンクライアントの概略要求:http://localhost:8901/api/nutrition/foods/4492/measures/7269?v=2
using System.Web.http.Dispatcher
public class CountingKsControllerSelector : DefaultHttpControllerSelector
{
private HttpConfiguraion _config;
public CountgKsControllerSelector(HttpConfiguraiton cofig) : base(config)
{
_config = config;
}
// HttpControllerDesriptor
public override System.Web.Http.Controllers.HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
// controller
var controllers = GetControllerMapping();
//
var routeData = request.GetRouteData();
// controller
var controllerName = (string)routeData.Values["controller"];
HttpControllerDescriptor descriptor;
if(controllers.TryGetValue(controllerName, out descriptor))
{
//var version = "2";
// QueryString
var version = GetVersionFromQueryString(request);
var newName = string.Concat(controllerName, "V", version);
HttpControllerDescriptor versionedDescriptor;
if(controllers.TryGetValue(newName, out versionedDescriptor))
{
return versionedDescriptor;
}
return descriptor;
}
return null;
}
// QueryString
private string GetVersionFromQueryString(HttpRequestMessage request)
{
var query = HttpUtility.ParseQueryString(request.RequestUri.Query);
var version = query["v"];
if(version != null)
{
return version;
}
return "1";
}
}
■Headerによるバージョンクライアントの概略要求:User-Agent:FiddlerHost:locahost:8901 X-CountingKs-Version:2
private string GetVersionFromHeader(HttpRequestMessage request)
{
const string HEADER_NAME = "X-CountingKs-Version";
if(request.Headers.Contains(HEADER_NAME))
{
var header = request.Headers.GetValues(HEADER_NAME).FirstOrDefault();
if(header != null)
{
return header;
}
}
return "1";
}
■Accept-Headerによるバージョンクライアントの実装要求:User-Agent:FiddlerHost:locahost:8901 Accept:アプリケーション/json;version=2
private string GetVersionFromAcceptHeaderVersion(HttpRequestMessage request)
{
var accept = request.Headers.Accept;
foreach(var mime in accept)
{
if(mime.MediaType == "applicaiton/json")
{
var value = mime.Parameters
.Where(v => v.Name.Equals("version",StringComparison.OrdinalIngoreCase))
.FirstOrDefault();
return value.Value;
}
}
return "1";
}
■MediaTypeによるバージョンのWebApiConfig.cs中
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().FirstOrDefault();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
CreateMediaTypes(jsonFormatter);
private static void CreateMediaTypes(JsonMediaTypeFormatter jsonFormatter)
{
var mediaTypes = new string[]
{
"application/vnd.counting,s.food.v1+json",
"application/vnd.countingks.measure.v1+json",
"application/vnd.countgks.measure.v2+json",
"applicatikon/vnd.countingks.diary.v1+json",
"application/vnd.countingks.diaryEntry.v1+json"
};
foreach(var mediaType in mediaTypes)
{
jsonFormatter.SupportedMeidaTypes.Add(new MediaTypeHeaderValue(mediaType));
}
}
クライアントでは、User-Agent:FiddlerHost:localhost:8901 Accept:application/vndといったように要求する.countingks.food.v1+json
private string GetVersonFromMediaType(HttpRequestMessage request)
{
var accept = request.Headers.Accept;
var ex = new Regex(@"application\/vnd\.countingks\.([a-z]+)\.v([0-9]+)\+json". RegexOptions.IgnoreCase);
foreach(var mime in accept)
{
var match = ex.Match(mime.MediaType);
if(match != null)
{
return match.Groups[2].Value;
}
}
return "1";
}
■SDammannを使用する.WebApi.Versioninghttps://github.com/Sebazzz/SDammann.WebApi.Versioning