问题描述
我们对我们网站的REST API。我们已经由$ P $版本端点pfixing与端点添加或更新与发布版本的端点。例如:
- / V1 /服务的一个
- / V2 /服务-B
- / V3 /服务-C
这种方法的问题是,我们有我们的客户code呼唤着不同版本的端点。例如,一个页面可以叫出/ V3 /服务-C和/ V1 /服务的一个。
我想设置它使我们的开发人员可以通过只prefixing端点与端点的最新版本访问最新版本的API。使用上面的例子,该网页将代替调出/ V3 /服务-c和/ V3 /服务一个,以及用于服务一个,该请求将被转发到绑定/ V1 /服务一个的动作,因为这是服务的最新版本之前/ V3。
我知道我可以只手动明确添加在code中的路线,但会得到难以管理端点的不同版本。
我知道如何从路由表中列举的版本,并解析他们。所以这部分就解决了。不过,我不知道在我是究竟是如何去拦截路由因此调用/ V3 / -service-A可以被转发到我有/v1/service-a.
任何想法?
想象一下,你声明你这样的路线:
config.Routes.MapHttpRoute(defaultVersioned,V {版本} / {}控制器/(编号),
新{ID = RouteParameter.Optional},{新版本= @\\ D +}); config.Routes.MapHttpRoute(默认,{}控制器/(编号),
新{ID = RouteParameter.Optional});
您现在可以创建独立的版本独立的控制器,使用特定的命名约定,例如:
公共类FooController的:ApiController {}公共类FooV2Controller:ApiController {}公共类FooV3Controller:ApiController {}
现在,因为版本是路线的一部分,可以实现自定义控制器选择,在那里你会捡起路由的版本,并选择基于相关的控制器。
公共类VersionAwareControllerSelector:DefaultHttpControllerSelector
{
公共VersionAwareControllerSelector(HttpConfiguration配置):基地(配置){} 公众覆盖字符串GetControllerName(HTT prequestMessage要求)
{
VAR controllerName = base.GetControllerName(请求);
VAR versionFinder =新VersionFinder();
VAR的版本= versionFinder.GetVersionFromRequest(请求); 如果(版本:0)
{
返回GetVersionedControllerName(请求controllerName,版本);
} 返回controllerName;
} 私人字符串GetVersionedControllerName(HTT prequestMessage要求,串baseControllerName,INT版)
{
VAR versionControllerName =的String.Format({0} V {1},baseControllerName,版本);
HttpControllerDescriptor描述;
如果(GetControllerMapping()。TryGetValue(versionControllerName,出描述符))
{
返回versionControllerName;
} 抛出新的Htt presponseException(request.CreateErrorResponse(
的HTTPStatus code.NotFound,
的String.Format(没有HTTP资源发现匹配URI的{0}和版本号{1},
request.RequestUri,版本)));
}
}
这code使用 VersionFinder
辅助类,可以发现<一个href=\"https://github.com/filipw/a$p$pss-recipes-webapi/blob/master/Chapter%2006/6-7/A$p$pss.Recipes.WebApi/A$p$pss.Recipes.WebApi/VersionFinder.cs\">here.
然后你只需要注册自定义选择:
config.Services.Replace(typeof运算(IHttpControllerSelector),新VersionAwareControllerSelector(配置));
对于一个完整的例子 - <一个href=\"https://github.com/filipw/a$p$pss-recipes-webapi/tree/master/Chapter%2006/6-7/A$p$pss.Recipes.WebApi/A$p$pss.Recipes.WebApi\">have看看这里Github上,它的的ASP.NET Web API 2食谱书的一部分。
We have a REST API for our site. We've been versioning endpoints by prefixing the endpoint with the release version the endpoint was added or updated with. For example
- /v1/service-a
- /v2/service-b
- /v3/service-c
The problem with this approach is we have our client code calling out to different versions of the endpoints. For example a page may call out to /v3/service-c and /v1/service-a.
I'd like to set it up so that our developers can access the latest version of the API by just prefixing the endpoints with the latest version of the endpoints. Using the example above, the page would instead call out to /v3/service-c and /v3/service-a, and for service-a, the request would be forwarded to the action bound to /v1/service-a because that was the latest version of the service prior to /v3.
I know I could just manually add the routes explicitly in code, but that would get difficult with managing different versions of endpoints.
I know how to enumerate the versions from the route table and parse them; so that part is solved. However, what I'm not sure on is how exactly I go about intercepting the the routing so that calls to /v3/-service-a can be forwarded to the route I have setup for /v1/service-a.
Any ideas?
Imagine you declare your routes like this:
config.Routes.MapHttpRoute("defaultVersioned", "v{version}/{controller}/{id}",
new { id = RouteParameter.Optional }, new { version = @"\d+" });
config.Routes.MapHttpRoute("default", "{controller}/{id}",
new { id = RouteParameter.Optional });
You can now create separate controllers for separate versions, using a specific naming convention for example:
public class FooController : ApiController {}
public class FooV2Controller : ApiController {}
public class FooV3Controller : ApiController {}
Now, since version is part of your route, you can implement a custom controller selector, where you'd pick up the version from the route and select a relevant controller based on that.
public class VersionAwareControllerSelector : DefaultHttpControllerSelector
{
public VersionAwareControllerSelector(HttpConfiguration configuration) : base(configuration) { }
public override string GetControllerName(HttpRequestMessage request)
{
var controllerName = base.GetControllerName(request);
var versionFinder = new VersionFinder();
var version = versionFinder.GetVersionFromRequest(request);
if (version > 0)
{
return GetVersionedControllerName(request, controllerName, version);
}
return controllerName;
}
private string GetVersionedControllerName(HttpRequestMessage request, string baseControllerName, int version)
{
var versionControllerName = string.Format("{0}v{1}", baseControllerName, version);
HttpControllerDescriptor descriptor;
if (GetControllerMapping().TryGetValue(versionControllerName, out descriptor))
{
return versionControllerName;
}
throw new HttpResponseException(request.CreateErrorResponse(
HttpStatusCode.NotFound,
String.Format("No HTTP resource was found that matches the URI {0} and version number {1}",
request.RequestUri, version)));
}
}
This code uses a VersionFinder
helper class, which can be found here.
Then you just have to register the custom selector:
config.Services.Replace(typeof(IHttpControllerSelector), new VersionAwareControllerSelector(config));
For a full example - have a look here on Github, it's part of the ASP.NET Web API 2 Recipes book.
这篇关于ASP.Net MVC:截取路由和转发至不同的动作/路线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!