[水煮 ASP.NET Web API2 方法论](12-3)OData 查询

问题

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 支持的完整的文档地址:http://docs.oasis-open.org/OData/new-in-OData/v4.0/cn01/new-in-OData-v4.0-cn01.html

查询项是在 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"
    }
  ]
}

就像上面提到的,我们可以通过在 Action 方法中使用
ODataQueryOptions 参数,来手动的实现询项。ODataQueryParameterBinding
会帮我完成将对象传入到 Action 的操作,这样我们就可以
Action 内部提取 OData 相关的查询项了。

清单 12-11. 在
Action 中使用 ODataQueryOptions

 1         public IQueryable<Player> GetAllPlayers(ODataQueryOptions queryOptions)
 2
 3         {
 4
 5             // 客户端传入的 top 和 skip
 6
 7             var filtered = db.Players.Skip(queryOptions.Skip.Value);
 8
 9             if (queryOptions.Top.Value > 0)
10
11             {
12
13                 filtered = filtered.Take(queryOptions.Top.Value);
14
15             }
16
17             return filtered.AsQueryable();
18
19         }
时间: 2024-10-21 14:22:30

[水煮 ASP.NET Web API2 方法论](12-3)OData 查询的相关文章

[水煮 ASP.NET Web API2 方法论](3-9)空气路由的设置

阅读导航 问题 解决方案 工作原理 代码演示 在此解释一下,空气路由,是本人臆想出来,觉着更能表达 IgnoreRoute 的意图,如果看着辣眼睛^^,请见谅. 问题 我们在之定义过集中式路由,集中式路由有一个特点就是短路,但是现在我们不想让某些路由工作(匹配并由路由引擎处理请求).那么我们应该怎么办呢? 解决方案 其实思路很简单,就是想把某些路由忽略了.ASP.NET WEB API 提供了一个叫做的 StopRoutingHandler 的处理器,简单说,他就是一个消息处理器,可以通过他来强

[水煮 ASP.NET Web API2 方法论](1-5)ASP.NET Web API Scaffolding(模板)

问题 我们想快速启动一个 ASP.NET Web API 解决方案. 解决方案 APS.NET 模板一开始就支持 ASP.NET Web API.使用模板往我们的项目中添加 Controller,在我们解决方案的 Controllers 文件夹上右键,选择"添加"->"Scaffolding". 即用模式,可以从下面选择一个: Web API2 Controller Web API2 Controller with      actions, using En

[水煮 ASP.NET Web API2 方法论](3-2)直接式路由/属性路由

问题 怎么样可以使用更贴近资源(Controller,Action)的方式定义路由. 解决方案 可以使用属性路由直接在资源级别声明路由.只要简单的在 Action 上使用属性路由 RouteAttribute,然后传一个相关路由模板就可以.属性路由与集中式路由在路由模板含义上基本是一样的,所有路由参数应该使用花括号,同时要与使用的 Action 相匹配.直接式路由支持默认路由,可选参数,约束.详细分析请往下走. 1 [Route("api/teams/{id}")] 2 public

[水煮 ASP.NET Web API2 方法论](1-4)从 MVC Controller 链接到 API Controller 以及反向链接

问题 想创建一个从 ASP.NET MVC controller 到 ASP.NET Web API controller 的直接链接,或者反向链接. 解决方案 可以使用 System.Web.Http.Routing.UrlHelp 的实例来创建一个指向 Controller的链接,来暴露ApiController(作为 Url 属性).着和在 RequestContext 上一样,会被附加到 HttpRequestMessage 实例.为了达到这个目的,我们需要调用链接方法或路由方法,然后传

[水煮 ASP.NET Web API2 方法论](1-8)添加 Session 状态

问题 ASP.NET Web API 构建 Web 应用程序时,要求使用 Session 在服务器存储一些用户特定的信息 解决方案 ASP.NET Web API 不支持 Session,因为 API 根本不依赖于System.Web.他想试图摆脱伪造 Session,非 HTTP这样的概念. 然而,如果我们 在 ASP.NET 运行时中运行 ASP.NET Web API,还想启用 Session.我们可以通过两种方式来做: 全局:应用于整个 API 局部:应用于指定路由 启用全局方式,我们需

[水煮 ASP.NET Web API2 方法论](1-6)Model Validation

问题 想要 ASP.NET Web API 执行模型验证,同时可以和 ASP.NET MVC 共享一些验证逻辑. 解决方案 ASP.NET Web API 与 ASP.NET MVC 支持一样的验证机制,都是通过System.ComponentModel.DataAnnoataions 的属性验证.使用框架提供的相关验证属性,已足够来用来验证模型. 想要更细粒度的验证,我们可以选择在我们的模型中实现 IValudateObject(来自于System.ComponentModel.DataAnn

[水煮 ASP.NET Web API2 方法论](1-7)CSRF-Cross-Site Request Forgery

问题 通过 CSRF(Cross-Site Request Forgery)防护,保护从 MVC 页面提交到ASP.NET Web API 的数据. 解决方案 ASP.NET 已经加入了 CSRF 防护功能,只要通过 System.web.Helpers.AntiForgery 类(System.Web.WebPages 的一部分)就可以. 他会生成两个 Token: Cookie Token 基于字符串的 Token 基于字符串的 Token 是可以嵌入到表单或者请求头(使用 Ajax 的情况

[水煮 ASP.NET Web API2 方法论](3-5)路由约束

问题 怎么样限制路由中参数的值. 解决方案 ASP.NET WEB API 允许我们通过 IHttpRouteConstraint 接口设置路由约束.集中式路由和直接式路由都可以使用 IHttpRouteConstraint. 框架提供了 18 个接口,他提供了大部分类型的约束,例如,路由参数长度相关的约束,可以确保值都在定义范围内,或者限制数据类型.当然也可以通过实现接口 IHttpRouteConstraint 来自定义约束逻辑. 工作原理 IHttpRoutConstraint 是一个 H

[水煮 ASP.NET Web API2 方法论](3-4)设置路由可选项

问题 怎么样创建一个路由,不管客户端传不传这个参数,都可以被成功匹配. 解决方案 ASP.NET WEB API 的集中式路由和属性路由都支持路由声明可选参数. 在用集中式路由中可以通过 RouteParameter.Optional 指定一个可选参数,RouteParameter.Optional 等同于MVC 中的 UrlParameter.Option. 属性路由,通过在可选参数后面添加一个问好作为后缀.同时,必须为其指定默认值 工作原理 从根本上看,ASP.NET WEB API 支持的