我正在 WebAPI(第一个)中开发一个 API,我在路由的特殊性方面遇到了一些问题,并将它们映射到我的控制器中用于嵌套资源的操作。
我有以下资源:
- 项目(根级资源)
- 站点(根级资源)
- 区域(站点的子资源)
所以我可以有一些时髦的嵌套,比如:
- /api/projects/1/sites
- /api/projects/1/sites/assigned
- /api/sites/1/zones
- /api/sites/1/zones/1
我遇到的问题是一些端点,特别是站点/区域的端点。我目前有两种 Get 方法,一种通过 siteId 和页面获取区域,另一种通过 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
好的,我有两个 GET 方法,虽然一个接受一个 int 和另外三个,所以我对为什么它变得混乱有点困惑,但我认为这归结为路由一个都是一个新概念。然后我要做的是为 ID 类型添加一个非常具体的路由处理程序并指向特定的操作方法:
config.Routes.MapHttpRoute(
name: "ZoneByIdApiRoute",
routeTemplate: "api/sites/{siteId}/zones/{id}",
defaults: new { Controller = "Zones", action="Get" }
);
太好了,那行得通……好吧,由于某种原因,非常具体的路线完全破坏了 PUT 方法,现在总是返回 405,我无法绕过它。
是否清楚地看到我在这里做错了什么?我可以创建更多控制器,但这似乎是在传递问题,我完全被卡住了。