2012-12-19 110 views
4

我遇到了ASP.NET Web API请求管道的执行顺序问题。路由和消息处理程序:请求处理订单问题

根据ASP.NET Web API文档(可用here),全局消息处理程序应该在路由机制之前执行。

Request pipeline

在该图像中,MessageHandler1是一个全球性的消息处理程序而MessageHandler2是特定于路线2


我创建了一个非常简单的例子来说明在执行顺序中似乎存在问题......或者我真的错过了一些重要的东西。

我有这个控制器

public class FooController : ApiController { 
    [HttpPut] 
    public string PutMe() { 
     return Request.Method.Method; 
    } 
} 

它只接受PUT请求。

该应用程序被配置为这样:

protected void Application_Start() { 
    var configuration = GlobalConfiguration.Configuration; 

    configuration.MessageHandlers.Add(new SimpleMethodOverrideHandler()); 
    configuration.Configuration.Routes.MapHttpRoute(
     name: "Foo", 
     routeTemplate: "api/foo", 
     defaults: new { controller = "foo", action = "putme" }, 
     constraints: new { put = new HttpPutOnlyConstraint() } 
    ); 
} 

SimpleMethodOverrideHandler是一个非常简单的DelegatingHandler,只是根据在所述查询串中的"method"参数改变请求的方法。

public class SimpleMethodOverrideHandler : DelegatingHandler { 
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { 
     var method = request.RequestUri.ParseQueryString()["method"]; 
     if(!string.IsNullOrEmpty(method)) { 
      request.Method = new HttpMethod(method); 
     } 
     return base.SendAsync(request, cancellationToken); 
    } 
} 

所以基本上,请求/api/foo?method=put在我的浏览器会火起来FooControllerPutMe方法。
事实上,正如前面所看到的,消息处理程序在将请求传递到HttpRoutingDispatched之前处理这些请求。

最后,这里是如何的constaint HttpPutOnlyConstraint定义:

public class HttpPutOnlyConstraint : IHttpRouteConstraint { 
    public bool Match(HttpRequestMessage request, 
         IHttpRoute route, 
         string parameterName, 
         IDictionary<string, object> values, 
         HttpRouteDirection routeDirection) { 
     return request.Method == HttpMethod.Put; 
    } 
} 

那么问题是,当我在我的浏览器内请求/api/foo?method=put,程序首先进入HttpPutOnlyConstraintMatch方法,这是错误。

如果我们引用先前链接的图像,则应该首先执行消息处理程序,但不幸的是它不是。

因此,当然,Match返回false并且没有找到该请求的控制器/操作,404发生。

如果我从路径定义中删除约束条件,程序将进入SimpleMethodOverrideHandler,请求的方法被成功修改,并且它能够匹配和执行我的控制器的方法。

我做错了什么?有没有一个秘密的配置参数知道为了做这样的事情? :-)

如果有人需要整个项目,它可用here [7KB zip file]

谢谢。

+1

我不太了解这个帖子,但认为它可以帮助你查看RouteMagic的源代码(https://github.com/Haacked/RouteMagic)。它使用动态注册的处理程序来拦截路由,但也有一些其他路由功能可能会从中获得灵感。 –

回答

3

您正在将路由引擎与Web API管道混淆。 HttpRoutingDispatcher不是一个路由引擎的概念。路由约束将首先被处理,因为您的基础主机需要构建路由表并匹配请求的路由。

HttpRoutingDispatcher是一个简单的HttpMessageHandler另一个实现和所有它是它检查已匹配路由的IHttpRoute,并选择下一个要调用的消息处理程序。如果不存在每个路由处理程序,它将处理委托给HttpControllerDispatcher