0

プロジェクトで 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 動詞で機能しないようです。つまり、HttpGetandHttpPut属性はアクションの使用を制限するだけで、コントローラー選択時の基準にはなりません。私は 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; }
}

ご回答ありがとうございます。

ヤン・カチーナ

4

1 に答える 1