Nat*_*n A 6 asp.net-web-api asp.net-web-api-routing
我将我的nuget包的Web API 2从RC1升级到5.0.0,并且傻眼了,发现曾经可以访问的HttpRouteBuilder是内置的.除此之外,HttpConfiguration.MapHttpAttributeRoutes不再存在重载,它将HttpRouteBuilder作为参数.为什么?
我正在使用它,它解决了我的项目中的一个主要问题.我该用什么呢?
背景:我正在编写一个使用Web API 2属性路由的服务器.我实现了一个继承自HttpRouteBuilder的类,这样我就可以为每个URI注入一些额外的路径段.例如,如果默认路由构建器最终为// myserver/user/update创建路由,则我的路由构建器会将该路由修改为// myserver/{instance}/user/update.我希望这是自动完成的,这样我就不必在我的数百个HttpGet,HttpPost等属性的每一个中都坚持这一点.那么现在我如何处理这一重大变化呢?
这种内部因素也破坏了我正在做的事情。
2013 年 8 月 21 日进行的更改集对api 进行了更改以解决此问题。根据该问题,删除功能的唯一原因是使 Web Api 更接近 MVC 的 api。我认为这并不是一个特别好的理由。
为了解决我的问题,我实现了一个IHttpActionSelector源自ApiControllerActionSelector. 我希望这不会是我的最终解决方案,因为对于一个简单的事情来说,代码确实太多了。这种方法也应该适用于您的问题。
在我的项目中,每个路由都需要根据在哪个程序集中找到它进行修改。在下面的简化代码中,每个路由都带有前缀/Api(在控制器之前RoutePrefixAttribute(如果存在))。
实际上IHttpActionSelector:
public class PrefixWithApiControllerActionSelector : WrappingApiControllerActionSelector {
protected override HttpActionDescriptor WrapHttpActionDescriptor(HttpActionDescriptor actionDescriptor) {
if (actionDescriptor is ReflectedHttpActionDescriptor)
return new PrefixWithApiReflectedHttpActionDescriptor((ReflectedHttpActionDescriptor)actionDescriptor);
return actionDescriptor;
}
}
public abstract class WrappingApiControllerActionSelector : ApiControllerActionSelector {
protected abstract HttpActionDescriptor WrapHttpActionDescriptor(HttpActionDescriptor actionDescriptor);
public override ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor) {
return base.GetActionMapping(controllerDescriptor).SelectMany(grouping => {
return grouping.Select(actionDescriptor => new KeyValuePair<string, HttpActionDescriptor>(grouping.Key, WrapHttpActionDescriptor(actionDescriptor)));
}).ToLookup(_ => _.Key, _ => _.Value);
}
}
Run Code Online (Sandbox Code Playgroud)
改变路线的部分:
public class PrefixWithApiHttpRouteInfoProvider : WrappedHttpRouteInfoProvider {
public PrefixWithApiHttpRouteInfoProvider(IHttpRouteInfoProvider infoProvider, HttpControllerDescriptor controllerDescriptor) : base(infoProvider, controllerDescriptor) { }
public override string Template {
get {
var parts = new List<string>();
parts.Add("Api");
var prefix = ControllerDescriptor.GetCustomAttributes<RoutePrefixAttribute>().FirstOrDefault();
if (prefix != null && !string.IsNullOrEmpty(prefix.Prefix)) {
parts.Add(prefix.Prefix);
}
if (!string.IsNullOrEmpty(InfoProvider.Template)) {
parts.Add(InfoProvider.Template);
}
var route = "~/" + string.Join("/", parts);
if (route.Length > 2 && route.EndsWith("/", StringComparison.Ordinal)) {
route = route.Substring(0, route.Length - 1);
}
return route;
}
}
}
public abstract class WrappedHttpRouteInfoProvider : IHttpRouteInfoProvider {
private readonly IHttpRouteInfoProvider _infoProvider;
private readonly HttpControllerDescriptor _controllerDescriptor;
protected WrappedHttpRouteInfoProvider(IHttpRouteInfoProvider infoProvider, HttpControllerDescriptor controllerDescriptor) {
_infoProvider = infoProvider;
_controllerDescriptor = controllerDescriptor;
}
public virtual string Name {
get { return InfoProvider.Name; }
}
public virtual string Template {
get { return _infoProvider.Template; }
}
public virtual int Order {
get { return InfoProvider.Order; }
}
protected HttpControllerDescriptor ControllerDescriptor {
get { return _controllerDescriptor; }
}
protected IHttpRouteInfoProvider InfoProvider {
get { return _infoProvider; }
}
}
Run Code Online (Sandbox Code Playgroud)
胶水:
public class PrefixWithApiReflectedHttpActionDescriptor : WrappedReflectedHttpActionDescriptor {
public PrefixWithApiReflectedHttpActionDescriptor(ReflectedHttpActionDescriptor descriptor) : base(descriptor) {}
public override Collection<T> GetCustomAttributes<T>(bool inherit) {
if (typeof(T) == typeof(IHttpRouteInfoProvider)) {
var attributes = Descriptor.GetCustomAttributes<T>(inherit).Cast<IHttpRouteInfoProvider>().Select(_ => new PrefixWithApiHttpRouteInfoProvider(_, Descriptor.ControllerDescriptor));
return new Collection<T>(attributes.Cast<T>().ToList());
}
return Descriptor.GetCustomAttributes<T>(inherit);
}
public override Collection<T> GetCustomAttributes<T>() {
if (typeof(T) == typeof(IHttpRouteInfoProvider)) {
var attributes = Descriptor.GetCustomAttributes<T>().Cast<IHttpRouteInfoProvider>().Select(_ => new PrefixWithApiHttpRouteInfoProvider(_, Descriptor.ControllerDescriptor));
return new Collection<T>(attributes.Cast<T>().ToList());
}
return Descriptor.GetCustomAttributes<T>();
}
}
public abstract class WrappedReflectedHttpActionDescriptor : ReflectedHttpActionDescriptor {
private readonly ReflectedHttpActionDescriptor _descriptor;
protected WrappedReflectedHttpActionDescriptor(ReflectedHttpActionDescriptor descriptor) : base(descriptor.ControllerDescriptor, descriptor.MethodInfo) {
_descriptor = descriptor;
}
public override HttpActionBinding ActionBinding {
get { return Descriptor.ActionBinding; }
set { Descriptor.ActionBinding = value; }
}
public override Collection<T> GetCustomAttributes<T>(bool inherit) {
return Descriptor.GetCustomAttributes<T>(inherit);
}
public override Collection<T> GetCustomAttributes<T>() {
return Descriptor.GetCustomAttributes<T>();
}
public override Collection<System.Web.Http.Filters.FilterInfo> GetFilterPipeline() {
return Descriptor.GetFilterPipeline();
}
public override Collection<System.Web.Http.Filters.IFilter> GetFilters() {
return Descriptor.GetFilters();
}
public override System.Collections.Concurrent.ConcurrentDictionary<object, object> Properties {
get { return Descriptor.Properties; }
}
public override IActionResultConverter ResultConverter {
get { return Descriptor.ResultConverter; }
}
public override Collection<HttpMethod> SupportedHttpMethods {
get { return Descriptor.SupportedHttpMethods; }
}
public override Collection<HttpParameterDescriptor> GetParameters() {
return Descriptor.GetParameters();
}
public override Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken) {
return Descriptor.ExecuteAsync(controllerContext, arguments, cancellationToken);
}
public override string ActionName {
get { return Descriptor.ActionName; }
}
public override Type ReturnType {
get { return Descriptor.ReturnType; }
}
protected ReflectedHttpActionDescriptor Descriptor {
get { return _descriptor; }
}
}
Run Code Online (Sandbox Code Playgroud)
要使用此功能,只需在配置中替换该IHttpActionSelector服务即可。PrefixWithApiControllerActionSelector
如果您找到更干净的做事方式,请发布您的解决方案!
| 归档时间: |
|
| 查看次数: |
657 次 |
| 最近记录: |