asp.net-web-api - HttpRouteBuilder - 它去了哪里,为什么?

标签 asp.net-web-api asp.net-web-api-routing

我将 Web API 2 的 nuget 包从 RC1 升级到了 5.0.0,然后惊讶地发现以前可以访问的 HttpRouteBuilder 变成了内部的。除此之外,不再有将 HttpRouteBuilder 作为参数的 HttpConfiguration.MapHttpAttributeRoutes 的重载。为什么?

我正在使用它,它解决了我项目中的一个主要问题。我改用什么?

背景:
我正在编写一个使用 Web API 2 的属性路由的服务器。我实现了一个从 HttpRouteBuilder 继承的类,这样我就可以向每个 URI 注入(inject)几个额外的路径段。例如,如果默认路由构建器最终为 创建了一个路由。//我的服务器/用户/更新 ,我的路线生成器会将该路线修改为 //myserver/{instance}/user/update .我希望它自动完成,这样我就不必在数百个 HttpGet、HttpPost 等属性中的每一个中都坚持这一点。那么现在我该如何处理这个重大变化呢?

最佳答案

那个内化也破坏了我正在研究的东西。

一个 change set made on August 21st 2013进行了此 api 更改以修复 this issue .根据该问题,删除功能的唯一原因是使 Web Api 更接近 MVC 的 api。在我看来,这不是一个特别好的理由。

为了解决我的问题,我实现了自定义 IHttpActionSelector源自 ApiControllerActionSelector .我希望它不会成为我的最终解决方案,因为对于一件简单的事情来说,它的代码实在太多了。这种方法也应该适用于您的问题。

在我的项目中,每条路线都需要根据它所在的程序集进行修改。在下面的简化代码中,每条路线都以 /Api 为前缀(在 Controller 的 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);
    }
}

改变路线的部分:
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; }
    }
}

胶水:
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; }
    }
}

要使用此功能,只需替换 IHttpActionSelector服务 PrefixWithApiControllerActionSelector在配置中。

如果您找到更清洁的做事方式,请发布您的解决方案!

关于asp.net-web-api - HttpRouteBuilder - 它去了哪里,为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19529522/

相关文章:

c# - ASP.NET Web API 性能问题

asp.net-web-api - AttributeRouting 不适用于 HttpConfiguration 对象来编写集成测试

c# - 发布参数始终为空

c# - ASP.NET Web API (.NET Core 3.1) 中的终结点路由问题

c# - 对象不与 child 一起添加 - EF Code First

asp.net - 从 ASP.NET Web API 中的 Controller 返回二进制文件

asp.net - Azure 物联网中心设备与后端的云通信

c# - Asp.Net Web API 防止记录重复

c# - args 在 Web API 属性路由注释中是如何表示的(如果有的话),如果不是,它们是如何被发现的?

c# - 基于 Accept header 的 Web API 操作选择