プロジェクトで Web API 2 属性ルーティングを使用して、データに JSON インターフェイスを提供しています。コントローラー選択の奇妙な動作に直面していますが、それがバグなのか機能なのかはまだ決まっていません:)私のアプローチについて説明しましょう。
属性ルーティングを使用して OData 構文をシミュレートしたいと考えています (設計原則により、OData の直接使用は拒否されています)。たとえば、id=5 のエンティティを取得するには、HTTP GET 要求を URI http://mydomain.com/api/Entity(5)に使用します。HTTP PUT動詞で同じURIを使用してエンティティを更新することを期待しています。ここから旅が始まる…
エンティティを取得するためのコントローラー (FirstController
以下の例) と、エンティティを変更するための別のコントローラー ( SecondController
) が必要です。どちらのコントローラーも同じ URI (例: http://mydomain.com/api/Entity(5) ) を処理します。唯一の違いは、URI で使用される HTTP 動詞です。GET は で処理されFirstController
、PUT は で処理されSecondController
ます。しかし、URI はそれらのどれによっても処理されません。代わりに HTTP 404 エラーが返されます。GET アクションと PUT アクションを 1 つのコントローラー ( でコメントアウトFirstController
) のみに「マージ」すると、両方の動詞が正しく処理されます。私は IIS Express を使用しており、従来のルートはすべて無効になっています。属性ルーティングのみが担当しています。
コントローラーの選択プロセスが HTTP 動詞で機能しないようです。つまり、HttpGet
andHttpPut
属性はアクションの使用を制限するだけで、コントローラー選択時の基準にはなりません。私は MVC や Web API の基礎にあまり詳しくないので、大きな質問をさせてください。
前に説明した動作は、MVC / Web API 2 によって意図的に実装された機能ですか、それとも修正されるバグですか?
それが機能と見なされると、設計原則に従うことができなくなります。「マージされた」コントローラーと一緒に暮らすことはできますが、それでもそれを悪い習慣と考えています...または、私の考えの中で何かが欠けていますか?
私の環境設定:
- Windows 7 (Oracle VirtualBox を使用する仮想マシン)
- ビジュアル スタジオ 2013
- .NET 4.5.1
- ウェブ API 2
以下はFirstController
クラスの実装です。
public class FirstController : ApiController
{
[HttpGet]
[Route("api/Entity({id:int})")]
public Output GetEntity(int id)
{
Output output = new Output() { Id = id, Name = "foo" };
return output;
}
//[HttpPut]
//[Route("api/Entity({id:int})")]
//public Output UpdateEntity(int id, UpdateEntity command)
//{
// Output output = new Output() { Id = id, Name = command.Name };
// return output;
//}
}
以下はSecondController
クラスの実装です。
public class SecondController : ApiController
{
[HttpPut]
[Route("api/Entity({id:int})")]
public Output UpdateEntity(int id, UpdateEntity command)
{
Output output = new Output() { Id = id, Name = command.Name };
return output;
}
}
以下は、説明されている動作をテストするためのコンソール アプリケーションの実装です。
class Program
{
static void Main(string[] args)
{
// HTTP client initialization
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("http://localhost:1567");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP GET - FirstController.GetEntity
HttpResponseMessage getEntityResponse = httpClient.GetAsync("/api/Entity(5)").Result;
Output getOutput = getEntityResponse.Content.ReadAsAsync<Output>().Result;
// HTTP PUT - SecondController.UpdateEntity
UpdateEntity updateCommand = new UpdateEntity() { Name = "newEntityname" };
HttpResponseMessage updateEntityResponse = httpClient.PutAsJsonAsync("/api/Entity(10)", updateCommand).Result;
Output updateOutput = updateEntityResponse.Content.ReadAsAsync<Output>().Result;
}
}
完了するために、以下が使用される DTO です。
public class UpdateEntity
{
public string Name { get; set; }
}
public class Output
{
public int Id { get; set; }
public string Name { get; set; }
}
ご回答ありがとうございます。
ヤン・カチーナ