【问题标题】:Custom route handlers in ASP.Net WebAPIASP.Net WebAPI 中的自定义路由处理程序
【发布时间】:2012-09-14 22:11:32
【问题描述】:

我能够在 global.asax.cs 中为 Web API 路由 ala 成功注册自定义路由处理程序(从 IRouteHandler 派生):

        routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "{client}/api/1.0/{controller}/{action}/{id}",
            defaults: new{id = UrlParameter.Optional}
        ).RouteHandler = new SingleActionAPIRouteHandler();

但是,当我尝试为 API 设置内存主机以进行集成测试时,我似乎找不到执行此操作的方法,当我调用 HttpConfiguration.Routes.MapRoute 时,我无法在返回 IHttpRoute。

我应该以不同的方式执行此操作(例如使用自定义 HttpControllerSelector)吗?我显然希望在这两种情况下都以同样的方式进行。

谢谢, 马特

编辑:

所以我最终做的基本上是遵循下面的建议,只是简单地覆盖 HttpControllerDispatcher 类,如下所示:

public class CustomHttpControllerDispatcher : HttpControllerDispatcher
{
    public CustomHttpControllerDispatcher(HttpConfiguration configuration) : base(configuration)
    {
    }
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // My stuff here

        return base.SendAsync(request, cancellationToken);
    }
}

【问题讨论】:

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


    【解决方案1】:

    你说的很对。自宿主返回 IHttpRoute 并以 HttpMessageHandler 作为参数。似乎没有内置方法来指定路由处理程序。

    更新:更清楚一点

    几乎可以肯定,您应该尝试使用 HttpControllerSelector 并实现自定义的...一个例子。 http://netmvc.blogspot.co.uk/

    接下来是一些实验,如果 HttpControllerSelector 不能满足您的要求,无论出于何种原因...

    但是,正如您所看到的,MapHttpRoute 确实对HttpMessageHandler 有重载,因此您可以对此进行试验...if the handler is NULL then it defaults to IHttpController 但您可以实现自己的并使用它来指向正确的控制器。 . MVC 框架似乎使用了[HttpControllerDispatcher]here,所以借用一些代码你也可以在这里放置你自己的控制器/路由选择代码——你可以访问路由和选择器,并且可以自己交换进出。

    此 CustomHttpControllerDispatcher 代码仅用于 DEMO...查找行

    //在这里做一些自定义来选择你的控制器

    也许可以玩一下……

    示例路线:

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional },
                constraints: null,
                handler: new CustomHttpControllerDispatcher(config)
            );
    

    CustomHttpControllerDispatcher 示例:

    public class CustomHttpControllerDispatcher : HttpMessageHandler
    {
            private IHttpControllerSelector _controllerSelector;
            private readonly HttpConfiguration _configuration;
    
            public CustomHttpControllerDispatcher(HttpConfiguration configuration)
            {
                _configuration = configuration;
            }
    
            public HttpConfiguration Configuration
            {
                get { return _configuration; }
            }
    
            private IHttpControllerSelector ControllerSelector
            {
                get
                {
                    if (_controllerSelector == null)
                    {
                        _controllerSelector = _configuration.Services.GetHttpControllerSelector();
                    }
                    return _controllerSelector;
                }
            }
    
            protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            {
                    return SendAsyncInternal(request, cancellationToken);
            }
    
            private Task<HttpResponseMessage> SendAsyncInternal(HttpRequestMessage request, CancellationToken cancellationToken)
            {
    
                IHttpRouteData routeData = request.GetRouteData();
                Contract.Assert(routeData != null);
    
                //DO SOMETHING CUSTOM HERE TO PICK YOUR CONTROLLER
                HttpControllerDescriptor httpControllerDescriptor = ControllerSelector.SelectController(request);
                IHttpController httpController = httpControllerDescriptor.CreateController(request);
    
                // Create context
                HttpControllerContext controllerContext = new HttpControllerContext(_configuration, routeData, request);
                controllerContext.Controller = httpController;
                controllerContext.ControllerDescriptor = httpControllerDescriptor;
    
                return httpController.ExecuteAsync(controllerContext, cancellationToken);
            }
    }
    

    【讨论】:

    • 非常感谢 Mark,我承认我对 WebAPI 框架的内部非常陌生,您能解释一下为什么这种方法比为配置提供自定义 IHttpControllerSelector 更好吗?看起来默认的 HttpControllerDispatcher 使用配置中定义的 ControllerSelector 来处理我想要做的工作。
    • @mattcole 我应该更清楚一点抱歉 - 我想确认您是正确的,并且我怀疑(正如您已经做过的那样)您应该查看自定义 HttpControllerSelector netmvc.blogspot.co.uk as如果您所做的只是转发到控制器,则偏好。我只是在想,也许您所做的不仅仅是选择控制器,而且可能还想使用除控制器等之外的其他处理程序...... CustomHttpControllerDispatcher 的想法有点像玩物和实验......抱歉没有更清楚。跨度>
    • 没问题马克,最后我选择了你建议的版本,因为我实际上只是更改了路由值中的一些值,我只是覆盖了 SendAsync 方法,完成了我的工作,然后让管道继续前进。
    • 如何停止进程并让它落在辅助节点中?我也做命名空间检查,如果存在相同命名空间列表中的 2 个匹配控制器,那么它的冲突,否则没关系,我只想从该特定命名空间获取控制器
    猜你喜欢
    • 1970-01-01
    • 2012-08-30
    • 1970-01-01
    • 2011-06-05
    • 2015-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-20
    相关资源
    最近更新 更多