私は Web API を使用して REST サービスを作成しました。Brian Mulloy によるこのWeb API 設計のセクションを読んだ後、Web API との関連付けを実装する方法を見つけようとしていました。
Web API 設計の抜粋:
協会
リソースは、ほとんどの場合、他のリソースとの関係を持っています。これらの関係を WebAPI で表現する簡単な方法は何ですか?
名詞でモデル化した API をもう一度見てみましょう。動詞は良くなく、dogs リソースと対話する API です。/dogs と dogs/1234 の 2 つのベース URL があったことを思い出してください。
リソースとコレクションを操作するために HTTP 動詞を使用しています。私たちの犬は飼い主のものです。特定の所有者に属するすべての犬を取得するか、その所有者の新しい犬を作成するには、GET または POST を実行します。
GET /owners/5678/dogs
POST /owners/5678/dogs現在、関係は複雑になる可能性があります。飼い主は獣医師と関係があり、犬と関係があり、食べ物と関係があります。これらをつなぎ合わせて 5 ~ 6 レベルの深さの URL を作成する人を目にすることは珍しくありません。1 つのレベルの主キーを取得したら、特定のオブジェクトを既に取得しているため、通常は上記のレベルを含める必要はありません。言い換えれば、URL が /resource/identifier/resource の上にあるものよりも深い場合はあまり必要ないはずです。
そこで、次のような関連付けのコントローラーメソッドを追加しようとしました。
public class EventsController : ApiController
{
// GET api/events
public IEnumerable<Event> Get()
{
// get list code
}
// GET api/events/5
public Event Get(int id)
{
// get code
}
// POST api/events
public void Post([FromBody]Event evnt)
{
// add code
}
// POST api/events/5
public void Post(int id, [FromBody]Event evnt)
{
// update code
}
// DELETE api/events/5
public void Delete(int id)
{
// delete code
}
// GET api/events/5/guests
public IEnumerable<Guest> Guests(int id)
{
// association code
}
}
また、ルート テンプレートを次のように変更しました。
config.Routes.MapHttpRoute("ApiWithAssociations",
"api/{controller}/{id}/{action}");
config.Routes.MapHttpRoute("DefaultApi",
"api/{controller}/{id}",
new { id = RouteParameter.Optional });
残念ながら、イベント リソースの更新/投稿を行うと、HTTP 500 内部サーバー エラーが発生し、応答本文は次のようになります。
リクエストに一致する複数のアクションが見つかりました
System.Web.Http.HttpPostAttribute (およびその他の HTTP 動詞) の追加と組み合わせてルート テンプレートを変更しようとしましたが、役に立ちませんでした。
誰かがこれを試して、それを機能させましたか? どんな助けでも大歓迎です。http動詞の倍数を持つことが絶対に不可能な場合は、RESTサービスとの関連付けを放棄する必要があると思います.
編集:解決策
Radim Köhler の回答を使用して、これを機能させることができました。次のように、HttpGetAttribute を Guests メソッドに追加します。
// GET api/event/5/guests
[HttpGet]
public IEnumerable<Guest> Guests(int id)
{
// association code
}
そして、次のようなデフォルトの GET アクションに対応する追加ルートを追加しました。
config.Routes.MapHttpRoute("DefaultGet",
"api/{controller}/{id}",
new {action = "Get"},
new {httpMethod = new HttpMethodConstraint(HttpMethod.Get)});
config.Routes.MapHttpRoute("ApiWithAssociations",
"api/{controller}/{id}/{action}");
config.Routes.MapHttpRoute("DefaultApi",
"api/{controller}/{id}",
new {id = RouteParameter.Optional});