fli*_*art 6 c# asp.net-web-api asp.net-web-api-routing
队列长篇介绍......
我有一个定义的资源
http://my-awesome-product.com/api/widgets/3
Run Code Online (Sandbox Code Playgroud)
它表示一个3的小部件id.在Web API中,我将定义一个控制器来为该资源提供服务,如下所示:
public class WidgetsController : ApiController
{
public Widget Get(int id)
{
return new Widget(...);
}
}
Run Code Online (Sandbox Code Playgroud)
现在,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; }
}
Run Code Online (Sandbox Code Playgroud)
通过这些Widget表示,客户端将请求在系统WidgetSummary中所有Widgets 的摘要网格上显示,它将FullWidgetForEditing在编辑页面上Widget请求特定的,并且它将请求WidgetForDropDownList在订单的下拉列表中使用形成.
据我了解关于REST,访问Widget应该有一个单一的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);
}
}
Run Code Online (Sandbox Code Playgroud)
然而,随着类型数量的增加并使单元测试更加困难,这会很快变得混乱.我真正想做的是以下内容:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
并具有基于媒体类型的特定操作方法的Web API路由.我调查覆盖了ApiControllerActionSelector,但是,我开始为此属性提取大量现有代码,因为我真的想要默认操作选择,但是在模糊操作的情况下,我想根据媒体类型过滤操作列表.我真的希望它是非侵入式的,这样我就可以将常规路由,标准属性路由(在Web API v2中)和这个假设属性路由混合在同一个控制器中(如果需要).
提问时间:目前是否可以使用Web API实现这样的路由策略?我是否必须完全重新ApiControllerActionSelector实现这一点(然后确保我的重新实现保持最新)?
所以这是你需要思考的问题。这真的是三种表示形式,还是三种不同的资源?如果您决定缓存这些表示,那么 URI 是否足以识别缓存的表示,或者您是否还需要更改接受标头?
如果您认为它们足够不同,可以作为资源,那么它们应该由不同的 URL 来标识。如果您决定在回复中使用超链接,您是否不希望能够独立于“widgeteditform”指向“widgetsummary”?
当您想要支持仅能够支持某些媒体类型的不同客户端设备时,通常需要多种表示。例如,设备 A 获取 Rep1,设备 B 获取 Rep2。您很少希望设备 A 同时访问设备 A 以及 Rep1 和 Rep2。
只是我的想法...