web-dev-qa-db-ja.com

MVC Web Apiのメソッドはどのようにhttp動詞にマッピングされますか?

次のリンクの5分のビデオで、1:10の時点で、Jon Gallowayは、DeleteCommentというメソッドを彼のCommentsControllerコントローラークラスに追加すると、慣例により、自動的にdelete http動詞にマップされると述べています。

WebApiを使用するMVCは、メソッドを正しい動詞にルーティングする方法をどのように知っていますか? global.asax.csファイルのルーティングがリクエストを正しいコントローラーにルーティングすることは知っていますが、削除リクエストはどのようにして削除メソッドやその他のメソッドに「規則に従ってマッピング」されますか?特に、動詞ごとに複数の方法がある場合はどうでしょうか? 「慣例により」は、メソッド名の最初のWordを見ているだけだと思いますが、そうであれば、メソッドのシグネチャを読み取って、2つの削除メソッドまたは2つの取得メソッドを区別する必要があります。これはすべて定義されていますか?

ビデオ: http://www.asp.net/web-api/videos/getting-started/delete-and-update

ありがとう!

編集:これは、WebApiテンプレートに含まれるサンプルのValuesControllerクラスのコードです。これが私の元の質問の出所でした。これら(およびコントローラーの他のメソッド)を区別する「慣習」はどのように機能しますか?

// GET /api/values
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET /api/values/5
    public string Get(int id)
    {
        return value;
    }
31

申し訳ありませんが、この投稿はあなたの質問から少し外れていますが、質問を読んだとき、このすべてが泡立ちました。

WebAPIマッチングセマンティック
defaultルート)WebAPIで使用される一致するセマンティックは、かなり単純です。

  1. アクション名と動詞を一致させます(動詞= GET?「get」で始まるメソッド名を探します)
  2. パラメータが渡された場合、APIはパラメータを持つアクションを探します

したがって、コードサンプルでは、​​パラメータのないGETリクエストは、パラメータのないGet*( )関数と一致します。 Getを含むIDはGet***(int id)を探します。


一致するセマンティクスは単純ですが、MVC開発者(少なくともこの開発者)に混乱を引き起こします。いくつかの例を見てみましょう:

奇数名-getメソッドは、「get」で始まる限り、任意の名前を付けることができます。したがって、ウィジェットコントローラの場合、関数にGetStrawberry()という名前を付けることができますが、それでも一致します。マッチングは次のように考えてください:methodname.StartsWith("Get")

複数の一致するメソッド-パラメータのない2つのGetメソッドがある場合はどうなりますか? GetStrawberry()およびGetOrange()。私がわかるように、コードで最初に定義された関数(ファイルの先頭)が勝つ...奇妙です。これには、コントローラーの一部のメソッドに到達できない(少なくともデフォルトのルートでは)となるという副作用があります。

[〜#〜]注[〜#〜]:ベータは「複数のメソッドのマッチング」のために上記のように動作しました-RC&リリースバージョンは少しですより多くのOCD。一致する可能性のあるものが複数ある場合は、エラーがスローされます。この変更により、あいまいな複数の一致の混乱が解消されます。同時に、同じコントローラ内でRESTとRPCスタイルのインターフェースを混在させることができ、順序と重複するルートに依存します。

何をしますか?
まあ、WebAPIは新しく、コンセンサスはまだ合体しています。コミュニティはRESTの原則をかなり達成しているようです。しかし、すべてのAPIがRESTfulである、またはRESTfulである必要はありません。RPCスタイルでより自然に表現されるAPIもあります。REST&人々が呼ぶものRESTは ちょっとだけ混乱well のソースのようです= 少なくともtoRoy Fielding

実用主義者として、私は多くのAPIが70%RESTfulであり、RPCスタイルのメソッドが散在していると思います。最初に、コントローラーの急増だけで(webapiバインディングメソッドが与えられた場合)、開発者の面倒を促進します。次に、WebAPIには、APIパスのネストされた構造を作成する組み込みの方法はありません(つまり、_/api/controller/_は簡単ですが、_/api/CATEGORY/Sub-Category/Controller_は実行可能ですが、苦痛です)。

私の観点からは、webAPIフォルダー構造がデフォルトのAPIパスを制御することを望んでいます...つまり、UIプロジェクトでカテゴリーフォルダーを作成すると、_/api/Category_がデフォルトのパスになります(何か 並列このMVC記事へ )。

私は何をしましたか?
それで、いくつかの要件がありました:(1)ほとんどの場合、落ち着いた構文を使用できること、(2)コントローラーの「名前空間」分離(サブフォルダーを考える)、(3)できること必要に応じて、追加のrpc-likeメソッドを呼び出す。これらの要件の実装は、巧妙なルーティングに帰着しました。

_// SEE NOTE AT END ABOUT DataToken change from RC to RTM

Route r;
r = routes.MapHttpRoute( name          : "Category1", 
                         routeTemplate : "api/Category1/{controller}/{id}", 
                         defaults      : new { id = RouteParameter.Optional } );
r.DataTokens["Namespaces"] = new string[] {" UI.Controllers.Category1"};

r = routes.MapHttpRoute( name          : "Category2", 
                         routeTemplate : "api/Category2/{controller}/{id}", 
                         defaults      : new { id = RouteParameter.Optional } );
r.DataTokens["Namespaces"] = new string[] {" UI.Controllers.Category2"};

routes.MapHttpRoute(     name          : "ApiAllowingBL", 
                         routeTemplate : "api/{controller}/{action}/{id}",
                         defaults      : new { id = RouteParameter.Optional } );

routes.MapHttpRoute(     name          : "DefaultApi",  
                         routeTemplate : "api/{controller}/{id}",           
                         defaults      : new { id = RouteParameter.Optional } );
_
  • 最初の2つのルートは「サブフォルダー」ルートを作成します。サブフォルダごとにルートを作成する必要がありますが、自分を主要なカテゴリに限定しているので、最終的にこれらの3〜10個しかありません。これらのルートがNamespaceデータトークンを追加して、特定のルートで検索されるクラスを制限する方法に注意してください。これは、UIプロジェクトにフォルダーを追加するときの典型的な名前空間の設定にうまく対応しています。
  • 3番目のルートでは、(従来のmvcのように)特定のメソッド名を呼び出すことができます。 Web APIはURLのアクション名を排除するため、このルートが必要な呼び出しを特定するのは比較的簡単です。
  • 最後のルートエントリは、デフォルトのWeb APIルートです。これはすべてのクラス、特に私の「サブフォルダ」の外にあるクラスをキャッチします。

Said Another Way
私の解決策は、コントローラーをもう少し分離することになり、_/api/XXXX_はあまり混雑しなくなりました。

  • UIプロジェクトにフォルダーを作成し(_Category1_とします)、そのフォルダー内にAPIコントローラーを配置します。
  • Visual Studioは、フォルダーに基づいてクラスの名前空間を自然に設定します。したがって、_Widget1_フォルダー内の_Category1_は、_UI.Category1.Widget1_のデフォルト名前空間を取得します。
  • 当然、私はAPIのURLにフォルダー構造(_/api/Category1/Widget_)を反映させる必要がありました。上記の最初のマッピングでは、_/api/Category1_をルートにハードコーディングすることでそれを実現し、次にnamespaceトークンが、一致するコントローラーを検索するクラスを制限します。

[〜#〜]注[〜#〜]:リリース時点では、DataTokensはデフォルトでnullです。 これはバグか機能か かどうかわかりません。だから私は少しヘルパーメソッドを書いて、私の_RouteConfig.cs_ファイルに追加しました...

_r.AddRouteToken("Namespaces", new string[] {"UI.Controllers.Category1"});

private static Route AddRouteToken(this Route r, string key, string[] values) {
  //change from RC to RTM ...datatokens is null
if (r.DataTokens == null) {
       r.DataTokens = new RouteValueDictionary();
    }
    r.DataTokens[key] = values;
    return r;
}
_

注2:@Jamie_Ideがコメントで指摘しているように、これはWebAPI 1の投稿だと思っていても、上記のソリューションはWebAPI 2では機能しません_IHttpRoute.DataTokens_にはセッターがありません。これを回避するには、次のような単純な拡張メソッドを使用できます。

_private static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, string[] namespaceTokens)
{   
    HttpRouteValueDictionary    defaultsDictionary      = new HttpRouteValueDictionary(defaults);
    HttpRouteValueDictionary    constraintsDictionary   = new HttpRouteValueDictionary(constraints);
    IDictionary<string, object> tokens                  = new Dictionary<string, object>();
                                tokens.Add("Namespaces", namespaceTokens);

    IHttpRoute route = routes.CreateRoute(routeTemplate, defaultsDictionary, constraintsDictionary, dataTokens: tokens, handler:null);
    routes.Add(name, route);

    return route;
}
_
59
EBarr

これはかなり頻繁に発生します。そして、それについてはさまざまな見方があります。個人的には今のところ特定のアイデアを購読していませんが、RESTコミュニティの間で、リソースごとに1つのコントローラを備えたものが最も人気があるようです。

したがって、基本的には次のことができます。

  1. ルートでアクションを公開します(Web APIはWord actionをMVCと同様に扱います)が、これは一般的に使用されることを意図していません。
  2. このように異なるパラメーターでメソッドを定義します post
  3. 私が言ったように、most推奨は、リソースごとに1つのコントローラーを使用することです。したがって、Web APIサンプルでも、エンティティーの収集用のコントローラーは、エンティティー自体のコントローラーとは異なります。 Rob Coneryによるこの post を読んでください here がGlennの答えです。
3
Aliostad