WebAPI (最初のもの) で API を開発していますが、ルートの特異性と、ネストされたリソースのコントローラーのアクションへのマッピングに問題があります。
次のリソースがあります。
- プロジェクト (ルート レベルのリソース)
- サイト (ルート レベルのリソース)
- Zones (サイトのサブリソース)
だから私はいくつかのファンキーな入れ子を持つことができます:
- /api/projects/1/sites
- /api/projects/1/sites/assigned
- /api/sites/1/zones
- /api/sites/1/zones/1
私が抱えている問題は、いくつかのエンド ポイント、特にサイト/ゾーンのものにあります。現在、2 つの Get メソッドがあります。1 つは siteId とページでゾーンを取得するメソッドで、もう 1 つは Id でゾーンを取得するメソッドです (以下のコードは面倒です。リファクタリングが必要ですが、WebAPI に頭を悩ませようとしています)。
public HttpResponseMessage Get(int id)
{
var resp = new HttpResponseMessage(HttpStatusCode.OK);
var zone = (from z in _repo
where z.Id == id
select z)
.SingleOrDefault()
.ToRepresentation<Zone, ZoneRepresentation>();
resp.Content = new ObjectContent<ZoneRepresentation>(zone, new JsonHalMediaTypeFormatter());
return resp;
}
public HttpResponseMessage GetByPage(int siteId, int page = DefaultPage, int pageSize = PageSize)
{
var resp = new HttpResponseMessage(HttpStatusCode.OK);
//TODO: Make sure access to project is checked....
var pagingInfo = (from z in _repo
where z.Site.Id == siteId
select z)
.GetPagingInfo<Zone>(pageSize);
if (pagingInfo.TotalRecords > 0)
{
if (page > pagingInfo.TotalPages)
{
resp.StatusCode = HttpStatusCode.NotFound;
throw new HttpResponseException(resp);
}
var zones = (from z in _repo.Include("Site")
where z.Site.Id == siteId
select z)
.OrderBy(z => z.Name)
.Paging(page, DefaultPage, pageSize)
.ToPagedRepresentation<Zone, ZoneListRepresentation>(pagingInfo.TotalRecords, pagingInfo.TotalPages, page, new Link("Zones", "/sites/" + siteId.ToString() + "/zones?page={page}"));
resp.Content = new ObjectContent<ZoneListRepresentation>(zones, new JsonHalMediaTypeFormatter());
}
else
{
resp.StatusCode = HttpStatusCode.NoContent;
throw new HttpResponseException(resp);
}
return resp;
}
追加のルートが指定されていないと、これらは機能しないため、アクセスしようとしています:
- /api/sites/1/zones
- /api/sites/1/zones/1
404 になります。
最初のルートを機能させるために、次のルート構成を追加します (より一般的なアプローチがあると確信していますが、これをできるだけ簡単に機能させたいだけです)。
config.Routes.MapHttpRoute(
name: "SiteZonesApiRoute",
routeTemplate: "api/sites/{siteId}/zones/{id}",
defaults: new { Controller = "Zones", id = RouteParameter.Optional }
);
これは最初のリンクで機能しますが、取得した ID を渡します。
ExceptionMessage":"Multiple actions were found that match the request:
System.Net.Http.HttpResponseMessage Get(Int32) on type API.Controllers.ZonesController
System.Net.Http.HttpResponseMessage GetByPage(Int32, Int32, Int32) on type
API.Controllers.ZonesController
1つは1つのintと他の3つを受け入れますが、私は2つのGETメソッドを持っています. 次に、ID タイプの非常に具体的なルート ハンドラを追加し、特定のアクション メソッドを指すようにします。
config.Routes.MapHttpRoute(
name: "ZoneByIdApiRoute",
routeTemplate: "api/sites/{siteId}/zones/{id}",
defaults: new { Controller = "Zones", action="Get" }
);
素晴らしい、それはうまくいきました......まあ、なんらかの理由で、非常に特定のルートが PUT メソッドを完全に壊し、常に 405 を返し、それを回避できません。
ここで私が間違ったことをしたことは明らかですか?さらにコントローラーを作成することもできますが、それは問題を回避しているようで、完全に立ち往生しています。