HttpRouteBuilder-哪里去了,为什么? [英] HttpRouteBuilder - Where did it go and Why?

查看:80
本文介绍了HttpRouteBuilder-哪里去了,为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我将用于Web API 2的nuget程序包从RC1升级到5.0.0,并傻眼地发现原来可访问的HttpRouteBuilder是内部的.随之而来的是,不再以HttpRouteBuilder作为参数的HttpConfiguration.MapHttpAttributeRoutes重载.为什么?

I upgraded my nuget package for the Web API 2 from the RC1 to 5.0.0, and was dumbfounded to find that HttpRouteBuilder, which used to be accessible, was made internal. Along with that, there is no longer an overload for HttpConfiguration.MapHttpAttributeRoutes that takes HttpRouteBuilder as an argument. Why?

我正在使用它,它解决了我项目中的一个主要问题.我该怎么用呢?

I was using that, and it solves a major problem in my project. What do I use instead?

背景: 我正在编写使用Web API 2的属性路由的服务器.我实现了一个从HttpRouteBuilder继承的类,以便可以向每个URI注入几个额外的路径段.例如,如果默认路由构建器最终为//myserver/user/update 创建路由,则我的路由构建器会将该路由修改为//myserver/{instance}/user/更新.我希望自动完成此操作,这样我就不必将其粘贴在数百个HttpGet,HttpPost等属性中的每一个中.那么,现在我该如何应对这一重大变化?

Background: I am writing a server that uses Attribute Routing for Web API 2. I implemented a class that inherited from HttpRouteBuilder so that I could inject a couple extra path segments to every URI. For example, if the default route builder ended up creating a route for //myserver/user/update, my route builder would modify that route to //myserver/{instance}/user/update. I wanted this done automatically so that I didn't have to stick that in every single of my hundreds of HttpGet, HttpPost, etc. attributes. So now how do I handle that with this major change?

推荐答案

这种内部构造破坏了我正在研究的东西.

That internalling broke something I was working on as well.

2013年8月21日进行的更改集进行了此api更改,以修复此问题.根据该问题,删除功能的唯一原因是使Web Api更接近MVC的api.我认为这不是特别好的理由.

A change set made on August 21st 2013 made this api alteration to fix this issue. According to that issue the only reason functionality was removed was to make Web Api closer to MVC's api. Not a particularly good justification in my opinion.

为解决我的问题,我实现了一个自ApiControllerActionSelector派生的自定义IHttpActionSelector.我希望这不会成为我的最终解决方案,因为对于一件简单的事情而言,实际上的代码太多了.这种方法也应适用于您的问题.

To resolve my issues I implemented a custom IHttpActionSelector derived from ApiControllerActionSelector. I hope it is not going to be my final solution since it really is far too much code for a simple thing. This approach should work for your problem too.

在我的项目中,需要根据找到的程序集修改每条路由.在以下简化代码中,每条路由都以/Api为前缀(如果存在控制器的RoutePrefixAttribute,则为前缀).

In my project each route needs to be modified according to which assembly it was found in. In following simplified code every route is prefixed with /Api (before a controller's RoutePrefixAttribute if present).

实际的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.

To use this functionality just substitute the IHttpActionSelector service with PrefixWithApiControllerActionSelector in the config.

如果您发现一种更清洁的处理方式,请发布您的解决方案!

If you find a cleaner way of doing things please post your solution!

这篇关于HttpRouteBuilder-哪里去了,为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆