miso_soup3 Blog

主に ASP.NET 関連について書いています。

ASP.NET Web API の Route Debugger が凄かった

ASP.NET Web API の Route Debugger を試してみました。
ルーティングがどのように選択されているかを確認したり、
思った通りにアクションメソッドにマッピングできない時の調査に大変役立ちます。

元の記事はこちらです。Debugging ASP.NET Web API with Route Debugger

デバッガーを実行するまで

Route Debugger は NuGet を使って、自分のプロジェクトに配置することができます。
ApiController が追加してあるプロジェクトを用意し、
(もしなければ、Web API テンプレートで新規作成しても試せます)
パッケージマネージャで以下の様に打ち込みます。

PM> Install-Package WebApiRouteDebugger

すると、プロジェクトに RouteDebugger のエリアが追加され、中にページやクラスファイルが沢山含まれていることが確認できます。

(.NET 4 の場合、async/await でエラーになる現象が。その場合は追加されたクラスにて、async/awaitを使わない書き方に変更する必要があります。)

プロジェクトをデバッグし、localhost:****/rd にアクセスします。
デバッグを行いたい Httpメソッドと URL を入力し、「Send」ボタンを押します。

すると・・・

該当するルートデータや、どの Controller、Action が選択されたかを、緑のハイライトで教えてくれます。
もし該当するルートがなかったり、コントローラーが見つからないといった場合は、
ハイライトされずに表示されます。

凄いところ

全ての候補が表示される

該当したルートの情報だけでなく、登録されているルーティング設定や Controller、Action もすべて表示してくれます。

例えばこんなルーティング設定を行っていると…、

Handler や Constraints まで、すべて表で記載されます。

Controller もすべて表示されます。
Action は、該当した Controller の範囲内ですべて表示されます。

アクションメソッド選択の詳細まで

アクションメソッドの選択については、かなり詳細に教えてくれます。
該当しなかったアクションメソッドについても「なぜ該当しなかったのか」を教えてくれます。

たとえば、ValuesController に以下の2つのメソッドが用意してあるとします。

public IEnumerable<string> Get() {};
public string Get(int id) {};

登録しているルーティング設定は、デフォルトのものです。

api/{controller}/{id}

この状況で、GET ~/api/values をデバッグしてみると、
Action selecting のセクションでは以下の様に表示されます。

注目する部分は、該当していないアクションについても、右側に True, False と書いてある部分です。
これは、どちらも HTTPメソッドによる判定はOKだったけど(By HTTP Verb 列)、パラメータによる判定(Parameter 列、int id の引数があるかどうか)が一方しかOKではなかったことを表しています。
他の項目、NonAction というのは、メソッドに[NonAction]属性が付けられていないかどうかの判定です。
By Action Name は、ルーティング設定で action が指定された時に判定されます。
これらの項目は、左から右へ、判定される順番に並んでいます。

これはルーティングをミスした時にかなり役に立つ情報です・・・!

仕組み

この Route Debugger は、knockout.js を使っており Single Page Application の構成になっています。
デバッグを実行した時、JavaScript 側で以下のようなにリクエストを送信しており、
リクエストヘッダーに RouteInspecting:true を追加しています。

$.ajax({
    url: $("#testRoute").val(),
    type: $("#testMethod").val(),
    beforeSend: function (xhr) {
        xhr.setRequestHeader("RouteInspecting", "true");
    }
})
.done(onSuccess)
.error(onFail);

このヘッダーの値は、HttpMessageHandler を継承した InspectHandler クラスでチェックされ、
そこがデバッグ用の処理を挟むかどうかの分かれ道になっています。

ルーティングについて この先

ASP.NET Web API のルーティングは、多くの人が”変わっている”と思っているのでしょうか…??
ロードマップには、属性でルーティングを指定する機能が含まれています。

Attribute routing in Web API

public class OrdersController : ApiController
{
    [HttpGet("orders/{id}")]
    public Order Get(int id) { }
    [HttpPost("orders/{id}/approve")]
    public void Approve(int id) { }
}

確かに、ルーティング設定箇所と、Controller クラスを見比べするのは大変ですので、
こんな風に属性で指定できるとなると楽になりそうです。