2012-12-19 148 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