HttpRouteBuilder - 它去了哪里以及为什么?

2024-02-01

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

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

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


这种内部因素也破坏了我正在做的事情。

A 2013 年 8 月 21 日进行的更改 http://aspnetwebstack.codeplex.com/SourceControl/changeset/2c71056731959debf3e6d3e764270b1fc51956aa对此 api 进行了更改以修复这个问题 http://aspnetwebstack.codeplex.com/workitem/1229。根据该问题,删除功能的唯一原因是使 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);
    }
}

改变路线的部分:

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在配置中。

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

HttpRouteBuilder - 它去了哪里以及为什么? 的相关文章

随机推荐

  • Swagger 漂亮的 HTML 代码在哪里?

    只有uglyHTML 页面可下载 HTML HTML2 和动态都丑陋 但该网站 例如 已编辑https app swaggerhub com apis user project version 以及许多其他 提供漂亮的 HTML 界面 如何
  • 使用 C 替换文件中的单词

    如何使用以下命令将文件中的单词替换为另一个单词C 例如 我有一个文件 其中包含 my friend name is sajid 我想替换这个词friend with 祖父 使得该文件更改为 my grandfather name is sa
  • R 中的 Excel YIELD 函数

    我试图弄清楚 Excel 中的 YIELD 函数如何运行其计算 以便我可以在 R 中创建一个使用类似输入的类似函数 以下是有关该函数的 Excel 文档 http office microsoft com en us excel help
  • 如何从 _layout SharePoint 页面使用网站母版页?

    我想在我的 SharePoint 12 hive template layouts TelephoneBookList test aspx 文件中使用母版页文件 如果有意义的话 就是网站的母版页文件 但是 每当我将 MasterPageFi
  • Mysql:每月记录数(包括零)

    我正在尝试计算表中的记录并按日期对它们进行分组 我当前的查询如下所示 SELECT count MONTH time as month YEAR time as year FROM myTable GROUP BY month year O
  • 使用 Swing 和 Graphics2D 在 Java 中旋转轮子?

    我正在研究一个可以绕中心旋转轮子的课程 轮子是使用graphics2d创建的 但我无法确切地弄清楚如何让轮子绕中心旋转 目前 轮子旋转 但不完全围绕原点旋转 我的最终目标是创建一个具有多种颜色的轮子以及围绕它的程序 但我主要关心的是让旋转轮
  • 我用的plyr对吗?我似乎使用了太多内存

    我有以下有点大的数据集 gt dim dset 1 422105 25 gt class dset 1 data frame gt 在不执行任何操作的情况下 R 进程似乎占用了大约 1GB 的 RAM 我正在尝试运行以下代码 dset lt
  • Jenkins job DSL 插件 - 隐藏参数

    我正在使用詹金斯隐藏参数插件 https wiki jenkins ci org display JENKINS Hidden Parameter Plugin但我找不到像使用其他参数那样在 DSL 中编写它的语法 例如 https jen
  • ImportError:使用 Jupyter Notebook 时没有名为 numpy 的模块 - Google Cloud Dataproc

    在 Google Dataproc 上启动 Jupyter Notebook 时 导入模块失败 我尝试使用不同的命令安装模块 一些例子 import os os sytem sudo apt get install python numpy
  • 使用 Python、文件

    我有一些需要读取的数据文件 我知道我应该使用 Dataset 但是有没有一种方法可以下载这些文件 而无需手动下载 而是通过其 URL 来下载 在我的例子中会是什么样子 我正在使用 conda python 和 netCDF4 无论我做什么
  • 如何在 Yii2 中进行多次 UPSERT?

    我正在使用 Yii2 高级模板 我必须在 MySql 数据库中插入 1000 到 2000 条记录 是否可以制作多个UPSERT 查询 in Yii2 请帮助我提供您的建议 答案 谢谢 从版本 2 0 14 开始 您可以使用 upsert
  • pandas:添加具有其他两列中任意一列的值的新列

    pd DataFrame A None 2 None None 3 4 B 1 2 3 4 5 6 A B 0 NaN 1 1 2 2 2 NaN 3 3 NaN 4 4 3 5 5 4 6 如何添加列C这将从列中获取值A如果不是 NaN
  • 如何将车辆品牌的 NCIC 代码值转换为 DCCIS 代码值?

    业务分析师告诉业务规则这已经改变了 现在他们希望我首先检查 计数 以查看是否有多个 NcicCode 在 VehicleMakeMapping 查找文档中 与 MncisCode 在输入文档中 匹配 如果 VehicleMakeMappin
  • Xcode 5.1 构建 opencv 在 64 位模拟器上失败

    我将 Xcode 更新到 5 1 使用 opencv 框架 2 4 的 iOS 应用程序项目中出现了许多错误 我的电脑是 macbook air 和 OSX 10 9 2 当我编译我的项目时 当我使用 Iphone Retina 3 5 英
  • ssis中动态表创建和加载数据

    我对 ssis 有一点疑问 文本文件具有基于位置的位置数据 需要在 sql server 中动态创建表并使用 ssis 包加载相关位置数据 源文本文件具有如下所示的示例数据 编号 名称 地点 1 abc 海德 2 巴努 陈 3 杰 邦 4
  • 正则表达式在页面上查找单词,包括内部标签

    谢谢切坦 萨斯特里 https stackoverflow com users 31284 chetan sastry我有这个正则表达式代码来解析我的页面以获取单词列表并将 TM 添加到其中 var wordList jQuery UI j
  • 如果大于批处理文件

    我编写了一个简单的批处理文件来根据数字选择运行常用网站 这是我的代码 我正在尝试设置它 以便如果有人输入 6 或更大的数字 它将转到 N但每当我输入 6 时 批处理文件就会退出 我努力了if input gt 6 goto N但它只是告诉我
  • WordPress Rest api响应发送html内容类型问题,URL中带有正斜杠

    从我的自定义 WordPress Rest api 中 我需要将以下文本作为内容类型 html 返回 OK ImageSendURL www yourdomain xxx Plugin DownloadOrders 这是我返回相同内容的代码
  • 如何使用加特林将 scala 类导入到另一个类中?

    注意 我是加特林新手 对 Scala 几乎一无所知 我正在开始将负载测试从 Jmeter 转换为加特林 我被困在如何组织代码库上 我找到的所有示例都是单个文件示例 如何将代码从一个模拟类导入到另一个模拟类中 我现在有这个类和测试场景 pac
  • HttpRouteBuilder - 它去了哪里以及为什么?

    我将 Web API 2 的 nuget 包从 RC1 升级到了 5 0 0 然后傻眼地发现原来可以访问的 HttpRouteBuilder 变成了内部的 除此之外 不再有以 HttpRouteBuilder 作为参数的 HttpConfi