14

我能够在 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);
    }
}
4

1 回答 1

13

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

更新:要清楚一点

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

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

但是,正如您所看到的那样,MapHttpRoute确实有一个重载,HttpMessageHandler因此您可以对此进行试验...如果处理程序为 NULL,则它默认为 IHttpController但您可以实现自己的并使用它来指向正确的控制器... MVC 框架似乎在[HttpControllerDispatcher] 这里使用,因此借用一些代码,您也可以在这里放置您自己的控制器/路由选择代码 - 您可以访问路由和选择器,并且可以自己将其换入和换出。

此 CustomHttpControllerDispatcher 代码仅用于演示...查找该行

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

也许可以玩一下...

示例路线:

        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);
        }
}
于 2012-09-13T13:25:08.067 回答