4

ASP.NETWebAPIリクエストパイプラインの実行順序に問題があります。

ASP.NET Web APIドキュメント(ここで入手可能)によると、グローバルメッセージハンドラーはルーティングメカニズムの前に実行されることになっています。

パイプラインをリクエストする

この画像でMessageHandler1は、はグローバルメッセージハンドラですが、ルート2MessageHandler2に固有です。


実行順序に問題があるように見えることを示すために、非常に簡単な例を作成しました…または、重要な何かが本当に欠けています。

私はこのコントローラーを持っています

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

最後に、制約の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され、リクエストのメソッドが正常に変更され、コントローラーのメソッドと一致して実行できるようになります。

私は何か間違ったことをしていますか?そのようなことをするために知っておくべき秘密の構成パラメーターはありますか?:-)

プロジェクト全体が必要な場合は、ここ[7KBzipファイル]から入手できます。

ありがとうございました。

4

1 に答える 1

3

ルーティングエンジンとWebAPIパイプラインを混同しています。HttpRoutingDispatcherルーティングエンジンの概念ではありません。基盤となるホストがルートテーブルを作成し、リクエストのルートと一致する必要があるため、ルート制約が最初に処理されます。

HttpRoutingDispatcherは単にの別の実装であり、一致したルートをHttpMessageHandler調べて、次に呼び出すメッセージハンドラーを選択するだけです。IHttpRouteルートごとのハンドラーが存在しない場合は、処理をに委任しHttpControllerDispatcherます。

于 2012-12-19T18:54:06.043 に答える