1. ホーム
  2. asp.net

[解決済み] Web API ルーティング - api/{controller}/{action}/{id} "dysfunctions" api/{controller}/{id}

2023-02-04 01:14:13

質問

Global.asaxにデフォルトのRouteがあります。

 RouteTable.Routes.MapHttpRoute(
         name: "DefaultApi",
         routeTemplate: "api/{controller}/{id}",
         defaults: new { id = System.Web.Http.RouteParameter.Optional }
         );

特定の機能をターゲットにできるようにしたかったので、別のルートを作りました。

RouteTable.Routes.MapHttpRoute(
         name: "WithActionApi",
         routeTemplate: "api/{controller}/{action}/{id}",
         defaults: new { id = System.Web.Http.RouteParameter.Optional }
         );

ということで、私のコントローラでは

    public string Get(int id)
    {
        return "object of id id";
    }        

    [HttpGet]
    public IEnumerable<string> ByCategoryId(int id)
    {
        return new string[] { "byCategory1", "byCategory2" };
    }

呼び出し .../api/records/bycategoryid/5 を呼び出すと、欲しいものが手に入ります。 しかし .../api/records/1 を呼び出すと、エラーが発生します。

リクエストにマッチするアクションが複数見つかりました: ...

ルートは有効なURLを定義するだけですが、関数のマッチングに関しては、両方の Get(int id)ByCategoryId(int id) マッチ api/{controller}/{id} というのは を混乱させる フレームワークを混乱させるものです。

デフォルトのAPIルートを再び動作させるために何をする必要がありますか? {action} ? という名前の別のコントローラを作成しようと思いました。 RecordByCategoryIdController という名前の別のコントローラを作成し、デフォルトのAPIルートに一致させ、それに対して .../api/recordbycategoryid/5 . しかし、私はそれがquot;dirty"(したがって不満足な)解決策であることがわかります。これに関する答えを探しましたが、ルートで {action} を使用するルートについてのチュートリアルは、この問題についてさえ言及していません。

どのように解決するのですか?

ルートエンジンは、あなたがルールを追加したときと同じ順序で使用します。最初にマッチしたルールを取得すると、他のルールのチェックを止め、これをコントローラやアクションの検索に利用します。

ですから、あなたは

  1. 特定のルールを一般的なルール (デフォルトなど) よりも優先させる、つまり RouteTable.Routes.MapHttpRoute を使用して、最初に "WithActionApi"、次に "DefaultApi" をマップすることを意味します。

  2. を削除します。 defaults: new { id = System.Web.Http.RouteParameter.Optional } というのは、idがオプションになると、"/api/{part1}/{part2}"のようなurlは決して"DefaultApi"に入らなくなるからです。

  3. どのアクションに入るかをルートエンジンに伝えるために、"DefaultApi"に名前付きアクションを追加してください。そうしないと、コントローラ内に複数のアクションがある場合、エンジンはどれを使うべきかわからず、 "Multiple actions were found that match the request: ..." をスローします。次に、Get メソッドと一致させるために ActionNameAttribute .

というわけで、ルートはこのようになります。

// Map this rule first
RouteTable.Routes.MapRoute(
     "WithActionApi",
     "api/{controller}/{action}/{id}"
 );

RouteTable.Routes.MapRoute(
    "DefaultApi",
    "api/{controller}/{id}",
    new { action="DefaultAction", id = System.Web.Http.RouteParameter.Optional }
);

そして、あなたのコントローラ。

[ActionName("DefaultAction")] //Map Action and you can name your method with any text
public string Get(int id)
{
    return "object of id id";
}        

[HttpGet]
public IEnumerable<string> ByCategoryId(int id)
{
    return new string[] { "byCategory1", "byCategory2" };
}