[水煮 ASP.NET Web API2 方法论](12

时间:2022-03-24 03:23:09

Web API 怎么支持通用的 OData 系统查询项,例如 $select 或 $filter。

解决方案

为了在 Web API 中启用查询项,我们需要在 Action 上使用 EnableQueryAttribute。

如果 Action 没有返回集合,而是返回单个对象的实例,调用端仍然可以使用 $expand 和 $select 两个查询语句,要达到这个目的,我们必须将返回对象包装在 SingleResult<T> 中。集合和单个对象实例作为返回值的例子如订单 12-7 所示

清单 12-7. 在两个路由上启用查询语句

1 public class PlayersController : ODataController 2 3 { 4 5 private readonly PlayersContext playersDbContext = new PlayersContext(); 6 7 [EnableQuery] 8 9 public IQueryable<Player> GetAllPlayers() 10 11 { 12 13 Return playersDbContext; 14 15 } 16 17 [EnableQuery] 18 19 public SingleResult<Player> GetSinglePlayers(int key) 20 21 { 22 23 return SingleResult.Create(playersDbContext.Where(x => x.Id == key).AsQueryable()); 24 25 } 26 27 }

工作原理

OData 查询选项是被定义在 OData 规范中,,如,查询字符串的参数控制的是返回资源的数量和顺序。ASP.NET Web API 几乎支持所有的标准查询项:

$expand:允许响应给客户端的信息包含关联资源(导航属性)

$select:限制返回的属性

$filter:过滤 Api 暴露出来的资源

$count:获取集合中实体的总数

$orderby:指定集合的排序 key

$skip:获取集合跳过的数量

$top:限制集合返回集合的数量

$format:请求特定的响应格式

唯一不支持的是 $search 查询参数。

小提示 可以查看 OData 4.0 支持的完整的文档地址:

查询项是在 ASP.NET Web API 中被 ODataQueryOption 类所描述的。EnableQueryAttribute 的工作方式实际是非常简单的。因为他是 Action 的 Filter,在 OnActionExecuted 方法中会获取 Action 的响应,并转换 HttpContent 为ObjectContent<T>。然后根据 HttpRequest 基于客户端的参数构造 ODataQueryOptions 实例,并返回相应的响应给客户端。如果响应是集合的话,可以响应客户端所有的查询项。如果响应不是集合,就会通过 ObjectContent 包装成 SingleResult<T>。这些时候,$expand 和 $select 都是可用的。

不使用 EnableQueryAttribute,也可以使用 ODataQueryOptions,他是可以接受 Action 的参数的。这种方式是通过自定义 HttpParameterBinding 类型的 ODataQueryParameterBinding 来支持的。我们也可以使用 ODataQueryOptions 实例中的信息手动执行相关查询。

在 Web API 中我们不需要完全掌握 OData 就可以体会到查询项给我们带来的便利。就算不是基于 ODataCotrollers,只要 Action 上使用了 EnableQueryAttribute 属性标签,我们还是可以在 Web API 上使用一些基础查询项,例如,$top,$skip,$select。

代码演示

在 Controller 的 Action 上使用 EnableQueryAttribute,这样的请求就可以使用 OData 查询项,如清单 12-7

Host/Plays(1)$select=Name,Team:使用 Player 实体的 Id 进行过滤,仅仅返回 Name 和 Team 两个属性。这个例子的响应,如清单 12-8.

清单 12-8. 从 OData 的 Web API 查询响应例子

{ "@OData.context":"http://localhost:43539/OData/$metadata#Players(Name,Team)/$entity","Name":"Name1","Team":"Team" } 

Host/Players?skip=1&$top=2:忽略集合中第一个实体,然后再剩下的实体中获取两个返回(可以理解为分页的第二页数据,每页大小是 2)。具体响应,如清单 12-9 所示。

清单 12-9. 从 OData 的 Web API 查询响应例子

{ "@OData.context":"http://localhost:43539/OData/$metadata#Players","value":[ { "Id":1,"Name":"Name1","Team":"Team" },{ "Id":2,"Name":"Name11","Team":"Team" } ] }

Host/Players?$format=application/json;OData.metadata=full&$filter=Team%20eq%20%27Team2%27:请求条件你为 Team 属性值为 Whales,以 json 格式返回 ,包含 OData 元数据的所有信息,包含类型和导航链接。具体响应结果,如清单 12-10 所示

{ "@OData.context":"http://localhost:43539/OData/$metadata#Players","value":[ { "@OData.type":"#BoiledCode.WebApi.Recipe.ODataDemo.Models.Player","@OData.id":"http://localhost:43539/OData/Players(3)","@OData.editLink":"http://localhost:43539/OData/Players(3)","Id":3,"Name":"Name2","Team":"Team2" },{ "@OData.type":"#BoiledCode.WebApi.Recipe.ODataDemo.Models.Player","@OData.id":"http://localhost:43539/OData/Players(4)","@OData.editLink":"http://localhost:43539/OData/Players(4)","Id":4,"Name":"Name21","Team":"Team2" } ] }