开放数据协议是微软设计的一个网络协议,旨在创建一个新的协议来通过 HTTP 查询和更新数据。OData 是一个 Open 协议,这意味着它有多种实现方法。
ASP.NET 网络应用编程接口内置了对 OData 的支持,因此您可以使用 HTTP 协议和 OData 语法查询您的资源。Visual Studio 2012 更新 2 或微软 ASP.NET 网络应用编程接口 OData NuGet 包添加了对网络应用编程接口的完整支持。
我们现在将构建一个支持 OData 的简单 API。
考虑这个控制器:
public class PostsController : EntitySetController<Post,int>
{
private readonly IPostRepository _repository;
public PostsController(IPostRepository repository)
{
_repository =
repository;
}
public override IQueryable<Post> Get()
{
IEnumerable<Post> posts= _repository.GetPosts();
return posts.AsQueryable();
}
}
这个控制器不是继承自通常的ApiController
,而是一个EntitySetController
。EntitySetController
是继承自ODataController
的抽象类,而ODataController
继承自ApiController
。
完整的层次结构是:
图 16:实体控制器层次结构
EntitySetController
只是一个专门的ApiController
,它有内置的工具来管理 OData 请求和构建 OData 响应。
在前面的例子中,控制器被声明为EntitySetController<Post, int>
。这两个通用参数表示该端点公开的实体类型和实体标识的类型。因此,邮政类可能是这样的:
public class Post
{
public int
Id { get; set;
}
public string Title { get; set; }
public string Author { get; set; }
public DateTime PublishingDate { get; set; }
}
然后我们覆盖EntitySetController
的Get
方法并实现它,这样它返回的列表就是IQueryable<Post>
。IQueryable
是 OData 控制器所需要的,OData 控制器使用它来添加最终在GET
请求中提供的查询。
这不足以使 OData 协议与 Web API 一起工作;我们需要更多的配置。在WebApiConfig
类中,我们必须添加以下代码:
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Post>("Posts");
Microsoft.Data.Edm.IEdmModel model =
modelBuilder.GetEdmModel();
config.Routes.MapODataRoute("ODataRoute", "odata", model);
config.EnableQuerySupport();
这段代码创建并配置了 OData 端点,并为 OData 请求定义了新的路由。请注意,新路线不会使用/api
路线,而是从MapODataRoute
中定义的odata
开始。另外需要注意的是,前面案例中的 URI 是区分大小写的,所以正确的 URI 会变成/odata/Posts
。
如果我们想启用 OData 的查询协议,则EnableQuerySupport
命令是必需的。
现在,我们准备启动应用程序并测试 OData 协议:
图 17:获取 OData 端点的简单方法
结果和默认的ApiController
没有太大区别。唯一真正的区别是属性odata.metadata
,它指定了一个网址,我们可以向它询问关于Post
资源的信息。如果我们援引 URI,我们获得:
图 18:资源元数据
该XML
描述了Post
资源,该资源显示属性及其类型,而不是实体的一般信息。
然而,OData 的真正强大之处在于,您可以使用特殊的语法生成请求,该语法使您能够创建复杂的查询来过滤、排序和聚合结果。
让我们从给 URI 增加一个订单条款开始:
/odata/Posts?$orderby=PublishingDate
orderby
选项指示 OData 引擎我们想要按发布日期排序的结果。我们不必修改代码,因为 ASP.NET 网络应用编程接口的 OData 模块解析查询字符串,过滤器应用于IQueryable
结果。
目前支持的选项有:top
、orderby
、filter
、inlinecount
和skip
。
orderby
用于指定结果必须如何排序。默认排序是升序,但是我们可以使用以下语法指定排序类型:
/odata/Posts?$orderby=Author desc
我们还可以组合不同的属性:
/odata/Posts?$orderby=Author,PublishingDate
/odata/Posts?$top=2
top
用于指定要退回的物品数量。对于$top=2
,我们是说我们只想要两个元素。
/odata/Posts?$filter=Author%20eq%20'ema'
filter
用于限制结果(类似于 SQL 中的“where”子句)。在这个例子中,我们请求了作者“ema”的帖子。
filter
也可以与布尔和比较运算符一起使用。
表 7: OData 布尔运算符
| 操作员 | 描述 | C#等效 | | 情商 | 平等的 | == | | -不知道 | 不平等 | != | | 大型旅行车的 | 大于 | > | | 通用电气公司 | 大于或等于 | >= | | 它 | 不到 | < | | 务实贸易(Labor Exchange)ˌ低爆速炸药(Low Explosive)ˌ职业介绍所(Labour Exchange) | 小于或等于 | <= | | 和 | 和 | && | | 或者 | 或者 | || |
使用这些运算符,我们可以创建更复杂的查询:
/odata/Posts?$filter=Author%20eq%20'ema'%20and%20Title%20eq%20'post2'
/odata/Posts?$filter=Author%20eq%20'ema'%20or%20Author%20eq%20'tessa'
inlinecount
用于添加集合中项目数量的信息:
/odata/Posts?$inlinecount=allpages
allpages
值在 OData 规范中定义,必须包括 URI 标识的集合中实体数量的计数(在应用 URI 上存在的任何$filter
系统查询选项后)。
Skip
用于跳过第一个 n 个值,只返回下一个:
/odata/Posts?$skip=2
在本例中,skip
只返回列表中从第三个元素开始的元素。
OData 的能力远不止这些;该协议还规定了修改资源的方式,但细节超出了本书的范围。
OData 是一种有趣的技术,可以用来查询我们的 API。OData 端点不是用各种参数创建许多端点来匹配整个可能的请求,而是用几行代码就解决了大多数问题。在本章中,我们看到了它是如何工作的,以及用于构建查询的基本语法。