我正在开发WebAPI(First One)中的API,我遇到了路由特定问题,并将它们映射到控制器中针对嵌套资源的操作。
我有以下资源:
所以我可以有一些时髦的嵌套:
我遇到的问题是一些终点,特别是站点/区域终点。我目前有两个Get方法,一个是通过siteId和page获取区域,另一个是通过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;
}
如果没有指定其他路线,则这些路线不起作用,因此尝试访问:
将导致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而我无法绕过它。
能否清楚地看到我在这里做错了什么?我可以创建更多的控制器,但这似乎传递了问题,我完全卡住了。
答案 0 :(得分:0)
如果您的控制器方法的签名与您的路线匹配,它应该有效。
您写道,您希望匹配以下路线:
即,siteId是必需参数,id(zoneId)是可选的。
这意味着你应该有一个名为Get或GetSomething的控制器方法,它将siteId和id作为参数。 Id可以是可选的,或者您可以使用另一个只有siteId作为参数的方法。
E.g。这会奏效:
public class ZonesController : ApiController
{
// /api/sites/1/zones/1
public HttpResponseMessage Get(int siteId, int id)
{
return Request.CreateResponse<string>(HttpStatusCode.OK, string.Format("siteId: {0}. Id: {1}", siteId, id));
}
// /api/sites/1/zones?page=12&pageSize=30
public HttpResponseMessage GetByPage(int siteId, int page = 0, int pageSize = 10)
{
return Request.CreateResponse<string>(HttpStatusCode.OK, string.Format("siteId: {0}. page: {1}", siteId, page));
}
}
路线配置:
config.Routes.MapHttpRoute(
name: "SiteZonesApiRoute",
routeTemplate: "api/sites/{siteId}/zones/{id}",
defaults: new { Controller = "Zones", id = RouteParameter.Optional }
);