私は基本的に、私はこの記事に続く、versionned APIを作るしようとしています:私はのように私のWEBAPIためのいくつかのルートを設定しているhttps://blogs.msdn.microsoft.com/webdev/2013/03/07/asp-net-web-api-using-namespaces-to-version-web-apis/どのバージョンのWeb APIを名前空間を使用する - 〜/ API/V1 /製品
をこれは:
namespace WebApiApplication {
public static class WebApiConfig {
public static void Register(HttpConfiguration config) {
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{version}/{controller}",
defaults: new { version = "v2" }
);
config.Routes.MapHttpRoute(
name: "DefaultApiWithId",
routeTemplate: "api/{version}/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Services.Replace(typeof(IHttpControllerSelector), new NamespaceHttpControllerSelector(config));
}
}}
私のプロジェクトには、「v1」と「v2」という2つのフォルダが含まれているControllersフォルダがあります。
〜/コントローラ/ V1/ProductsController.cs
namespace WebApiApplication.Controllers.v1 {
[RoutePrefix("api/v1/products")]
public class ProductsController : ApiController {
Product[] products = new Product[] {
new Product { UserReference = 1, Name = "product1" },
new Product { UserReference = 2, Name = "product2" }
};
[HttpGet]
[Route("")]
public IEnumerable<Product> GetAllProducts() {
return products;
}
[HttpGet]
[Route("{userReference}")]
public IHttpActionResult GetProducts(int userReference) {
var res = products.Where(t => t.UserReference == userReference);
if (res == null)
return NotFound();
return Ok(res);
}
}}
〜/コントローラ/ V2/ProductsController.cs
namespace WebApiApplication.Controllers.v2 {
[RoutePrefix("api/v2/products")]
public class ProductsController : ApiController {
Product[] products = new Product[] {
new Product { UserReference = "a", Name = "product1" },
new Product { UserReference = "b", Name = "product2" }
};
[HttpGet]
[Route("")]
public IEnumerable<Product> GetAllProducts() {
return products;
}
[HttpGet]
[Route("{userReference}")]
public IHttpActionResult GetProducts(string userReference) {
var res = products.Where(t => t.UserReference == userReference);
if (res == null)
return NotFound();
return Ok(res);
}
}}
バージョン間の唯一の違いは、次のとおりです。コントローラは、このようになります。 UserReferenceはV2の文字列になります。
私は両方のバージョンで同じコントローラ名を持っているので、私は要求されたコントローラを見つけるために、現在の「IHttpControllerSelector」を上書きする必要があります。
〜/ NamespaceHttpControllerSelector.cs
public class NamespaceHttpControllerSelector : IHttpControllerSelector {
private const string VERSION_KEY = "version";
private const string CONTROLLER_KEY = "controller";
private readonly HttpConfiguration _configuration;
private readonly Lazy<Dictionary<string, HttpControllerDescriptor>> _controllers;
private readonly HashSet<string> _duplicates;
public NamespaceHttpControllerSelector(HttpConfiguration configuration) {
_configuration = configuration;
_duplicates = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
_controllers = new Lazy<Dictionary<string, HttpControllerDescriptor>>(InitializeControllerDictionary);
}
public HttpControllerDescriptor SelectController(HttpRequestMessage request) {
IHttpRouteData routeData = request.GetRouteData();
if (routeData == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
string versionName = GetRouteVariable<string>(routeData, VERSION_KEY); // Here, I am always getting null
if (versionName == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
string controllerName = GetRouteVariable<string>(routeData, CONTROLLER_KEY);
if (controllerName == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
// Find a matching controller.
string key = string.Format(CultureInfo.InvariantCulture, "{1}.{2}", versionName, controllerName);
HttpControllerDescriptor controllerDescriptor;
if (_controllers.Value.TryGetValue(key, out controllerDescriptor)) {
return controllerDescriptor;
}
else if (_duplicates.Contains(key)) {
throw new HttpResponseException(
request.CreateErrorResponse(
HttpStatusCode.InternalServerError,
"Multiple controllers were found that match this request."));
}
else {
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
public IDictionary<string, HttpControllerDescriptor> GetControllerMapping() {
return _controllers.Value;
}
private Dictionary<string, HttpControllerDescriptor> InitializeControllerDictionary() {
var dictionary = new Dictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);
// Create a lookup table where key is "namespace.controller". The value of "namespace" is the last
// segment of the full namespace. For example:
// MyApplication.Controllers.V1.ProductsController => "V1.Products"
IAssembliesResolver assembliesResolver = _configuration.Services.GetAssembliesResolver();
IHttpControllerTypeResolver controllersResolver = _configuration.Services.GetHttpControllerTypeResolver();
ICollection<Type> controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver);
foreach (Type t in controllerTypes) {
var segments = t.Namespace.Split(Type.Delimiter);
// For the dictionary key, strip "Controller" from the end of the type name.
// This matches the behavior of DefaultHttpControllerSelector.
var controllerName = t.Name.Remove(t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length);
var key = string.Format(
CultureInfo.InvariantCulture,
"{0}.{1}",
segments[segments.Length - 1],
controllerName);
// Check for duplicate keys.
if (dictionary.Keys.Contains(key)) {
_duplicates.Add(key);
}
else {
dictionary[key] = new HttpControllerDescriptor(_configuration, t.Name, t);
}
}
// Remove any duplicates from the dictionary, because these create ambiguous matches.
// For example, "Foo.V1.ProductsController" and "Bar.V1.ProductsController" both map to "v1.products".
foreach (string s in _duplicates) {
dictionary.Remove(s);
}
return dictionary;
}
private static T GetRouteVariable<T>(IHttpRouteData routeData, string name) {
object result = null;
if (routeData.Values.TryGetValue(name, out result))
return (T) result;
return default(T);
}
}
を問題があります"SelectController"メソッドで。 「versionName = GetRouteVariable(routeData、VERSION_KEY);」を実行しているとき、私は常にversionNameに「null」を取得しています。 (私が "http://localhost:27039/api/v1/products/1"と呼ぶとき)。
私が代わりにURLに要求されたバージョンを持っている必要があります...
私のGlobal.asax.cs:
namespace WebApiApplication {
public class WebApiApplication : System.Web.HttpApplication {
protected void Application_Start() {
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}}
これは単なるテストにすぎないことは知っていますが、コントローラを1つだけ作成して「api/v1」に公開することをお勧めします。次に、新しいバージョンをお持ちの場合は、バージョンコントロールに新しいブランチを作成し、それを 'api/v2'に公開することができます。たとえば、1つのバグを修正する必要があるとしましょう。同じアプリの2つのバージョンを表す1つのアプリであるため、戦略2ではバージョン2も公開する必要があります。 –
2つのバージョンの唯一の違いは、Product UserReferenceがV2の文字列になることです –