路由和消息处理程序:请求处理订单问题
我遇到了ASP.NET Web API请求管道的执行顺序问题。
根据ASP.NET Web API文档( 此处提供 ),全局消息处理程序应该在路由机制之前执行。
在此图像上, MessageHandler1
是全局消息处理程序,而MessageHandler2
特定于Route 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 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
我的浏览器会启动FooController
的PutMe
方法。
实际上,如前所述,消息处理程序在将请求传递给HttpRoutingDispatched
之前处理HttpRoutingDispatched
。
最后,这是如何定义HttpPutOnlyConstraint
:
public class HttpPutOnlyConstraint : IHttpRouteConstraint { public bool Match( HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary values, HttpRouteDirection routeDirection ) { return request.Method == HttpMethod.Put; } }
那么问题是,当我请求/api/foo?method=put
在我的浏览器中时,程序首先输入HttpPutOnlyConstraint
的Match
方法,这是错误的。
如果我们引用先前链接的图像,则应该首先执行消息处理程序,但遗憾的是它不是。
因此,当然, Match
返回false
并且没有找到请求的控制器/操作,404发生。
如果我从路由定义中删除约束,程序进入SimpleMethodOverrideHandler
,请求的方法会成功更改,并且能够匹配并执行我的控制器方法。
难道我做错了什么? 是否有秘密配置参数要知道才能做这些事情? 🙂
如果有人需要整个项目,可以在这里找到[7KB zip文件] 。
谢谢。
您将路由引擎与Web API管道混淆。 HttpRoutingDispatcher
不是路由引擎概念。 将首先处理路径约束,因为您的基础主机需要构建路由表并匹配您的请求的路由。
HttpRoutingDispatcher
只是HttpRoutingDispatcher
的另一个实现,它所做的就是检查已匹配的路由的IHttpRoute
,并选择接下来要调用的消息处理程序。 如果不存在每个路由处理程序,它会将处理委托给HttpControllerDispatcher
。