排队长介绍...
我有一个资源定义在
http://my-awesome-product.com/api/widgets/3
它表示一个id
3 的小部件。在 Web API 中,我将定义一个控制器来提供该资源,如下所示:
public class WidgetsController : ApiController
{
public Widget Get(int id)
{
return new Widget(...);
}
}
现在,Widget
该类可能非常大,并且想要节省从数据库到 Web 服务器以及从 Web 服务器到客户端的带宽,我创建了几个 DTO 类,其中包含有限数量的整体Widget
. 例如:
public class WidgetSummary
{
public int Id { get; set; }
public string Code { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
}
public class FullWidgetForEditing
{
public int Id { get; set; }
public string Code { get; set; }
public string Description { get; set; }
public decimal Weight { get; set; }
public decimal Price { get; set; }
public Color Color { get; set; }
public decimal Width { get; set; }
public decimal Height { get; set; }
public decimal Depth { get; set; }
}
public class WidgetForDropDownList
{
public int Id { get; set; }
public string Code { get; set; }
}
使用这些Widget
表示,客户端将请求在系统中所有 sWidgetSummary
的摘要网格上显示,它会请求在特定的编辑页面上,并且它会请求在订单的下拉列表中使用形式。Widget
FullWidgetForEditing
Widget
WidgetForDropDownList
根据我对 REST 的理解,要访问 aWidget
应该有一个 URL,因为它是一个资源,无论其表示形式如何,并且客户端应指定Accept
带有媒体类型参数的标头以检索Widget
其不同形式,例如my-awesome-product.type=widgetsummary
、my-awesome-product.type=fullwidgetforediting
和my-awesome-product.type=widgetfordropdownlist
.
我可以通过检查请求的标头在 Web API 中实现这一点,如下所示:
public class WidgetsController : ApiController
{
public object Get(int id)
{
if (Request.Headers.Accept.Any(x => x.Parameters.Any(y => y.Name == "my-awesome-product.type" && y.Value == "widgetsummary")))
{
return new WidgetSummary(...);
}
else if (Request.Headers.Accept.Any(x => x.Parameters.Any(y => y.Name == "my-awesome-product.type" && y.Value == "fullwidgetforediting")))
{
return new FullWidgetForEditing(...);
}
else if (Request.Headers.Accept.Any(x => x.Parameters.Any(y => y.Name == "my-awesome-product.type" && y.Value == "widgetfordropdownlist")))
{
return new WidgetForDropDownList(...);
}
throw new HttpResponseException(HttpStatusCode.NotAcceptable);
}
}
但是,随着类型数量的增加,这会很快变得混乱,并使单元测试变得更加困难。我真正想做的是以下几点:
public class WidgetsController : ApiController
{
[HttpGet(MediaType = "my-awesome-product.type", MediaTypeValue = "widgetsummary")]
public WidgetSummary GetWidgetSummary(int id)
{
return new WidgetSummary();
}
[HttpGet(MediaType = "my-awesome-product.type", MediaTypeValue = "fullwidgetforediting")]
public FullWidgetForEditing GetFullWidgetForEditing(int id)
{
return new FullWidgetForEditing();
}
[HttpGet(MediaType = "my-awesome-product.type", MediaTypeValue = "widgetfordropdownlist")]
public WidgetForDropDownList GetWidgetForDropDownList(int id)
{
return new WidgetForDropDownList();
}
}
并根据媒体类型将 Web API 路由到特定的操作方法。我调查了覆盖ApiControllerActionSelector
,但是,我开始为该属性提取大量现有代码,因为我真的想要默认动作选择,但是在不明确的动作的情况下,我想根据媒体类型过滤动作列表. 我真的希望它是非侵入式的,以便我可以在需要时在同一个控制器中混合约定路由、标准属性路由(在 Web API v2 中)和这个假设的属性路由。
提问时间:目前是否可以使用 Web API 实现这样的路由策略?我是否必须完全重新实现ApiControllerActionSelector
才能实现这一点(然后确保我的重新实现保持最新)?