博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用ASP.NET Web API 2创建OData v4 终结点
阅读量:7011 次
发布时间:2019-06-28

本文共 8930 字,大约阅读时间需要 29 分钟。

开放数据协议(Open Data Protocol【简称OData】)是用于Web的数据访问协议。OData提供了一种对数据集进行CRUD操作(Create,Read,Update,Delete)的统一方式。

Asp.Net Web API支持该协议的v3 和v4版,甚至可以创建一个和v3终结点并排运行的v4终结点。
该博文演示了如何创建支持CRUD操作的OData v4终结点。

用到的软件版本

  • Web API 2
  • OData v4
  • VS 2013 Update 5
  • EF6
  • .Net 4.5.2

创建VS项目

在VS中创建一个新的Asp.Net Web应用项目,命名为“PersonsService”,如下图:

577014-20160122140755859-1662879820.png

然后继续看下图:

577014-20160122140809797-1705542893.png

安装OData Nuget包

打开Nuget包管理器控制台,输入以下命令:

Install-Package Microsoft.AspNet.Odata

该命令会安装最新版本的OData Nuget 包。

添加Model类

Model类是一个表示应用中的数据实体的对象。

在解决方案资源管理器中的Models文件夹下,创建一个Person类:

按照惯例,model类应该放在Models文件夹下,但是在你自己的项目中可以不这么做。

下面是我的Person类的代码:

namespace PersonsService.Models{    public class Person    {        public int Id { get; set; }        public string Name { get; set; }        public bool Gender { get; set; }        public string UserName { get; set; }    }}

启用Entity Framework

这篇博客,我们使用EF的Code First模式来创建数据库。

Web API OData不要求一定得是EF。只要数据访问层可以将数据库实体转换成model,使用任何数据访问层都可以。

首先,安装EF的Nuget包。在包管理器控制台中使用下面的命令:

Install-Package EntityFramework

打开Web.config文件,在configuration元素中添加下面的connectionStrings节点:

接下来,在Models文件夹下添加一个PersonsContext类:

using System.Data.Entity;namespace PersonsService.Models{    public class PersonsContext:DbContext    {        public PersonsContext()            : base("name=PersonsContext")        {        }        public DbSet
Persons { get; set; } }}

在构造函数中,"name=PersonsContext"指定了连接字符串的命名。

配置OData终结点

打开App_Start/WebApiConfig.cs文件,配置下面的新代码(删除自动生成的代码):

using System.Web.Http;using System.Web.OData.Builder;using System.Web.OData.Extensions;using PersonsService.Models;namespace PersonsService{    public static class WebApiConfig    {        public static void Register(HttpConfiguration config)        {            //新代码            ODataModelBuilder builder=new ODataConventionModelBuilder();            builder.EntitySet
("Persons"); config.MapODataServiceRoute( routeName:"odata", routePrefix:"odata", model:builder.GetEdmModel() ); } }}

上面的代码做了两件事:

  • 创建了一个实体数据模型(Entity Data Model【简称EDM】)。
  • 添加了一个路由。

EDM是一个抽象的数据模型。EDM用于创建服务元数据文档。ODataConventionModelBuilder类使用默认的命名规范创建了一个EDM。这种方式需要写的代码最少。如果你想更多地控制EDM,那么你可以使用 ODataModelBuilder类来创建EDM类,这样做就要显式添加属性,键和导航属性。

路由(route)会告诉Web API如何将HTTP请求路由到终结点。调用MapODataServiceRoute 扩展方法可以创建一个OData v4路由。

如果你的应用有了多个OData终结点,那么要为每个终结点创建一个单独的路由,给每个路由一个唯一的路由名和前缀(prefix)。

添加OData控制器

控制器是处理HTTP请求的一个类。在OData应用中,应该为每个实体集创建一个单独的控制器。而在这篇博客中,我们只要为Person实体创建一个控制器就行了。

在Controllers文件夹下添加一个控制器,如下:

577014-20160122145847078-1851015606.png

在Controllers文件夹上右键添加控制器,接下来选中上图的选择,因为还没有针对OData v4的基架。

默认已经帮我们生成了下面的代码,基本上我们不需要做什么了,CRUD全都有了,呵呵:

using System.Data.Entity.Infrastructure;using System.Linq;using System.Net;using System.Web.Http;using System.Web.Http.ModelBinding;using System.Web.OData;using PersonsService.Models;namespace PersonsService.Controllers{    /*    在为此控制器添加路由之前,WebApiConfig 类可能要求你做出其他更改。请适当地将这些语句合并到 WebApiConfig 类的 Register 方法中。请注意 OData URL 区分大小写。    using System.Web.Http.OData.Builder;    using System.Web.Http.OData.Extensions;    using PersonsService.Models;    ODataConventionModelBuilder builder = new ODataConventionModelBuilder();    builder.EntitySet
("Persons"); config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel()); */ public class PersonsController : ODataController { private PersonsContext db = new PersonsContext(); // GET: odata/Persons [EnableQuery] public IQueryable
GetPersons() { return db.Persons; } // GET: odata/Persons(5) [EnableQuery] public SingleResult
GetPerson([FromODataUri] int key) { return SingleResult.Create(db.Persons.Where(person => person.Id == key)); } // PUT: odata/Persons(5) public IHttpActionResult Put([FromODataUri] int key, Delta
patch) { Validate(patch.GetEntity()); if (!ModelState.IsValid) { return BadRequest(ModelState); } Person person = db.Persons.Find(key); if (person == null) { return NotFound(); } patch.Put(person); try { db.SaveChanges(); } catch (DbUpdateConcurrencyException) { if (!PersonExists(key)) { return NotFound(); } else { throw; } } return Updated(person); } // POST: odata/Persons public IHttpActionResult Post(Person person) { if (!ModelState.IsValid) { return BadRequest(ModelState); } db.Persons.Add(person); db.SaveChanges(); return Created(person); } // PATCH: odata/Persons(5) [AcceptVerbs("PATCH", "MERGE")] public IHttpActionResult Patch([FromODataUri] int key, Delta
patch) { Validate(patch.GetEntity()); if (!ModelState.IsValid) { return BadRequest(ModelState); } Person person = db.Persons.Find(key); if (person == null) { return NotFound(); } patch.Patch(person); try { db.SaveChanges(); } catch (DbUpdateConcurrencyException) { if (!PersonExists(key)) { return NotFound(); } else { throw; } } return Updated(person); } // DELETE: odata/Persons(5) public IHttpActionResult Delete([FromODataUri] int key) { Person person = db.Persons.Find(key); if (person == null) { return NotFound(); } db.Persons.Remove(person); db.SaveChanges(); return StatusCode(HttpStatusCode.NoContent); } protected override void Dispose(bool disposing) { if (disposing) { db.Dispose(); } base.Dispose(disposing); } private bool PersonExists(int key) { return db.Persons.Count(e => e.Id == key) > 0; } }}

该控制器借助EF,使用PersonsContext类来访问数据库。注意控制器重写了Dispose方法来释放 PersonsContext

生成数据库

通过Code First的Migration生成数据库,然后填充数据。关于如何使用CodeFirst生成数据库不是本节的重点,所以这里一笔带过。下面是我生成的数据库已经填充的数据:

577014-20160122161828437-190692613.png

查询实体集

自动生成的查询操作如下:

// GET: odata/Persons        [EnableQuery]        public IQueryable
GetPersons() { return db.Persons; } // GET: odata/Persons(5) [EnableQuery] public SingleResult
GetPerson([FromODataUri] int key) { return SingleResult.Create(db.Persons.Where(person => person.Id == key)); }

无参数的GetPersons()方法会返回整个Person表的集合。

GetPerson([FromODataUri] int key)方法会返回指定Id的Person。

[EnableQuery]特性允许客户端使用查询选项(如$filter,$sort和$page)修改查询。

操作演示

577014-20160122161345047-860283141.png

577014-20160122161439625-1644473315.png

新增实体

允许客户端将一个新的Person实体添加到数据库中:

// POST: odata/Persons        public IHttpActionResult Post(Person person)        {            if (!ModelState.IsValid)            {                return BadRequest(ModelState);            }            db.Persons.Add(person);            db.SaveChanges();            return Created(person);        }

更新实体

OData支持两种不同语义更新实体,包括PATCH和PUT。

  • PATCH执行一个部分更新,客户端只识别要更新的属性。
  • PUT会替换整个实体。

PUT的劣势在于客户端必须发送实体的所有属性,包括没有改变的值。

陈述了PATCH是首选。

下面是生成的代码:

// PATCH: odata/Persons(5)        [AcceptVerbs("PATCH", "MERGE")]        public IHttpActionResult Patch([FromODataUri] int key, Delta
patch) { Validate(patch.GetEntity()); if (!ModelState.IsValid) { return BadRequest(ModelState); } Person person = db.Persons.Find(key); if (person == null) { return NotFound(); } patch.Patch(person); try { db.SaveChanges(); } catch (DbUpdateConcurrencyException) { if (!PersonExists(key)) { return NotFound(); } else { throw; } } return Updated(person); }

在PATCH中,控制器使用了Delta类型来跟踪改变。

删除实体

允许客户端从数据库删除一个Person:

// DELETE: odata/Persons(5)        public IHttpActionResult Delete([FromODataUri] int key)        {            Person person = db.Persons.Find(key);            if (person == null)            {                return NotFound();            }            db.Persons.Remove(person);            db.SaveChanges();            return StatusCode(HttpStatusCode.NoContent);        }

转载地址:http://zwqtl.baihongyu.com/

你可能感兴趣的文章