8

URLにアクションが指定されていない場合、アクション名としてHTTP動詞を使用するWebAPIの組み込みのデフォルトロジックがあるようです。たとえば、次のルートがあります。

        config.Routes.MapHttpRoute(
            name: "DefaultApiController",
            routeTemplate: "api/{controller}"
        );

そして、これが私の行動です:

    public IEnumerable<Conference> Get()
    {
        ...
    }

    [ActionName("current")]
    public IEnumerable<Conference> GetCurrent()
    {
        ...
    }

GET動詞を使用して〜/ Conferencesに移動すると、「Get()」アクションが表示されます。POST動詞を使用する場合は、「Post([FromBody] Conferencevalue)」アクション...などに移動します。〜/ Conferences / GetCurrentに移動しようとすると([ActionName( "current")]が一番上にある場合でも)、競合が発生します。

リクエストに一致する複数のアクションが見つかりました:System.Collections.Generic.IEnumerable 1[MyApp.Models.Conference] Get() on type MyApp.Api.ConferencesController System.Collections.Generic.IEnumerable1 [MyApp.Models.Conference] GetCurrent()on type MyApp.Api.ConferencesController

これは、フレームワークがデフォルトのアクションを決定するためにEqualではなくStartsWithを使用していることを意味します。また、動詞をアクションに一致させるときにActionName属性を無視します。

私の質問は、StartsWithロジックを使用する代わりに、フレームワークのデフォルトのアクションを動詞に正確に一致させるにはどうすればよいですか?GET動詞は、Get()、GetCurrent()GetPast()などではなく、Get()アクションにのみ一致する必要があります(特に、ActionName属性を無視している場合)。

編集 簡単にするために、上記のルートの1つだけを示しました。まだドラフト中のすべてのルートを表示すると役立つと思います。独自のカスタムアクションを追加する余地を残しながら、完全に機能するRESTAPIを取得しようとしています。

    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApiControllerActionId",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: null,
            constraints: new { action = @"^[a-zA-Z]+$", id = @"^\d+$" } // action must start with character
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApiControllerActionName",
            routeTemplate: "api/{controller}/{action}/{name}",
            defaults: null,
            constraints: new { action = @"^[a-zA-Z]+$", name = @"^[a-zA-Z]+$" } // action and name must start with character
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApiControllerId",
            routeTemplate: "api/{controller}/{id}",
            defaults: null,
            constraints: new { id = @"^\d+$" } // id must be all digits
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApiControllerAction",
            routeTemplate: "api/{controller}/{action}",
            defaults: null,
            constraints: new { action = @"^[a-zA-Z]+$" } // action must start with character
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApiController",
            routeTemplate: "api/{controller}"
        );

更新 HTTP動詞の制約を追加すると、次のようになります。

        config.Routes.MapHttpRoute(
            name: "DefaultApiControllerGet",
            routeTemplate: "api/{controller}",
            defaults: new { action = "Get" },
            constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) }
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApiControllerPost",
            routeTemplate: "api/{controller}",
            defaults: new { action = "Post" },
            constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Post) }
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApiControllerPut",
            routeTemplate: "api/{controller}",
            defaults: new { action = "Put" },
            constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Put) }
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApiControllerDelete",
            routeTemplate: "api/{controller}",
            defaults: new { action = "Delete" },
            constraints: new { httpMethod = new HttpMethodConstraint(HttpMethod.Delete) }
        );
4

1 に答える 1

7

編集:あなたは質問に大きな編集を加えたので、私は応答を変更する必要があります:

つまり、これはデフォルトでアクションをディスパッチするため、WebAPIではそのままでは機能しません。

  1. {action}がルートデータの一部である場合、アクション名に基づく
  2. HTTP動詞に基づく

ただし、これら2つのアプローチを単一のコントローラーに混在させることはできないため、単一のコントローラーから両方のアプローチを使用してアクションをディスパッチすることはできません(これが実行しようとしていることです)。

これを修正するには、次の3つの方法があります。

  1. リソースを作り直して、アクション名のディスパッチと動詞ベースのディスパッチャリング用に別々のリソースを用意します(これは理想からはほど遠いです)

  2. ネストされたルートごとにルートを手動で登録します。このように、HTTP動詞でディスパッチし続けますが、ルーティングは明らかに特定のアクションを指します。AttributeRoutingこれを単純化するには、(https://github.com/mccalltd/AttributeRouting)のようなものを使用できます。欠点は、明らかに、アクションごとに1つのルートで終わることです。

  3. IActionSelector動詞ベースとアクション名ベースの両方のディスパッチを単一のコントローラーに混在させることができる新しいを実装します。これは最も「低レベル」のソリューションですが、あなたがやりたいこととまったく同じように見えます。先週、ウォークスルーを投稿しました-http ://www.strathweb.com/2013/01/magical-web-api-action-selector-http-verb-and-action-name-dispatching-in-a-single-controller //

于 2013-01-21T16:03:02.430 に答える