次のリンクの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;
}
申し訳ありませんが、この投稿はあなたの質問から少し外れていますが、質問を読んだとき、このすべてが泡立ちました。
WebAPIマッチングセマンティック
(defaultルート)WebAPIで使用される一致するセマンティックは、かなり単純です。
したがって、コードサンプルでは、パラメータのない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 } );
_
Namespace
データトークンを追加して、特定のルートで検索されるクラスを制限する方法に注意してください。これは、UIプロジェクトにフォルダーを追加するときの典型的な名前空間の設定にうまく対応しています。Said Another Way
私の解決策は、コントローラーをもう少し分離することになり、_/api/XXXX
_はあまり混雑しなくなりました。
Category1
_とします)、そのフォルダー内にAPIコントローラーを配置します。Widget1
_フォルダー内の_Category1
_は、_UI.Category1.Widget1
_のデフォルト名前空間を取得します。/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;
}
_
これはかなり頻繁に発生します。そして、それについてはさまざまな見方があります。個人的には今のところ特定のアイデアを購読していませんが、RESTコミュニティの間で、リソースごとに1つのコントローラを備えたものが最も人気があるようです。
したがって、基本的には次のことができます。