.NET Core开发日志之OData(Open Data Protocol)
简述
odata,即open data protocol,是由微软在2007年推出的一款开放协议,旨在通过简单、标准的方式创建和使用查询式及交互式restful api。
类库
在.net core中想要使用odata功能的话需要添加microsoft.aspnetcore.odata包。
dotnet add package microsoft.aspnetcore.odata
准备模型类
public class address { public string city { get; set; } public string street { get; set; } } public enum category { book, magazine, ebook } public class press { public int id { get; set; } public string name { get; set; } public string email { get; set; } public category category { get; set; } } public class book { public int id { get; set; } public string isbn { get; set; } public string title { get; set; } public string author { get; set; } public decimal price { get; set; } public address address { get; set; } public press press { get; set; } }
创建edm模型
odata使用edm,即entity data model来描述数据的结构。在startup文件中添加创建方法。
private static iedmmodel getedmmodel() { var builder = new odataconventionmodelbuilder(); builder.entityset<book>("books"); builder.entityset<press>("presses"); return builder.getedmmodel(); }
注册odata服务
在startup文件的configureservices方法里注册odata服务。
services.addodata(); services.addmvc(options => { options.enableendpointrouting = false; }).setcompatibilityversion(compatibilityversion.version_2_2);
这里要注意的是在.net core 2.2里,默认已经有终结点,所以要使用odata的终结点的话需要将默认选项禁用掉。
注册odata终结点
同样在startup文件里,在其configure方法内将原来的注册路由内容改为注册odata的终结点。
app.usemvc(b => { b.mapodataserviceroute("odata", "odata", getedmmodel()); });
显示元数据
运行程序后访问https://localhost:5001/odata/$metadata地址,可以看到所有可用模型的元数据。
<edmx:edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" version="4.0"> <edmx:dataservices> <schema xmlns="http://docs.oasis-open.org/odata/ns/edm" namespace="default"> <entitytype name="book"> <key> <propertyref name="id"/> </key> <property name="id" type="edm.int32" nullable="false"/> <property name="isbn" type="edm.string"/> <property name="title" type="edm.string"/> <property name="author" type="edm.string"/> <property name="price" type="edm.decimal" nullable="false"/> <property name="address" type="default.address"/> <navigationproperty name="press" type="default.press"/> </entitytype> <entitytype name="press"> <key> <propertyref name="id"/> </key> <property name="id" type="edm.int32" nullable="false"/> <property name="name" type="edm.string"/> <property name="email" type="edm.string"/> <property name="category" type="default.category" nullable="false"/> </entitytype> <complextype name="address"> <property name="city" type="edm.string"/> <property name="street" type="edm.string"/> </complextype> <enumtype name="category"> <member name="book" value="0"/> <member name="magazine" value="1"/> <member name="ebook" value="2"/> </enumtype> <entitycontainer name="container"> <entityset name="books" entitytype="default.book"> <navigationpropertybinding path="press" target="presses"/> </entityset> <entityset name="presses" entitytype="default.press"/> </entitycontainer> </schema> </edmx:dataservices> </edmx:edmx>
创建controller
本文实例中不考虑数据库的操作,故而使用hard code方式构建必要的模型对象。
public class bookscontroller : odatacontroller { private static ilist<book> books {get; set;} public bookscontroller() { books = new list<book> { new book { id = 1, isbn = "111-0-321-56789-1", title = "calculus", price = 66.6m, address = new address { city = "shanghai", street = "beijin xi road" }, press = new press { id = 1, name = "shanghai tongji", category = category.book } }, new book { id = 2, isbn = "222-2-654-00000-2", title = "linear algebra", price = 53.2m, address = new address { city = "shanghai", street = "beijin dong road" }, press = new press { id = 2, name = "shanghai fudan", category = category.ebook } } }; } [enablequery] public iactionresult get() { return ok(books); } [enablequery] public iactionresult get(int key) { return ok(books.firstordefault(b => b.id == key)); } }
enablequery特性在需要高级查询的场景时必须添加。
查询
加入controller之后,访问https://localhost:5001/odata/books地址,可得到所有book数据。
{ "@odata.context": "https://localhost:5001/odata/$metadata#books", "value": [ { "id": 1, "isbn": "111-0-321-56789-1", "title": "calculus", "author": null, "price": 66.6, "address": { "city": "shanghai", "street": "beijin xi road" } }, { "id": 2, "isbn": "222-2-654-00000-2", "title": "linear algebra", "author": null, "price": 53.2, "address": { "city": "shanghai", "street": "beijin dong road" } } ] }
访问https://localhost:5001/odata/books(1)地址,可得到key值为1的book数据。
{ "@odata.context": "https://localhost:5001/odata/$metadata#books/$entity", "id": 1, "isbn": "111-0-321-56789-1", "title": "calculus", "author": null, "price": 66.6, "address": { "city": "shanghai", "street": "beijin xi road" } }
高级查询
如果想要使用odata查询的高级功能,可以在注册终结点时额外加上相应的配置。
app.usemvc(b => { b.select().expand().filter().orderby().maxtop(100).count(); b.mapodataserviceroute("odata", "odata", getedmmodel()); });
访问网址时加上所需的查询内容:
https://localhost:5001/odata/books?$select=id,title
{ "@odata.context": "https://localhost:5001/odata/$metadata#books(id,title)", "value": [ { "id": 1, "title": "calculus" }, { "id": 2, "title": "linear algebra" } ] }
如果想要按特定条件过滤数据内容的话也很容易:
https://localhost:5001/odata/books?$filter=price%20le%2060
{ "@odata.context": "https://localhost:5001/odata/$metadata#books", "value": [ { "id": 2, "isbn": "222-2-654-00000-2", "title": "linear algebra", "author": null, "price": 53.2, "address": { "city": "shanghai", "street": "beijin dong road" } } ] }
总结
不难看出,odata的真正魅力在于其对那些高级查询功能的支持,所以在创建restful api时,不妨考虑使用odata,这样应该能减少许多不必要的代码工作。
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。