开放数据协议(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”,如下图:

然后继续看下图:

安装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节点:

  <connectionStrings>
<add name="PersonsContext" connectionString="Server=.;Database=PersonsDB;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>

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

using System.Data.Entity;

namespace PersonsService.Models
{
public class PersonsContext:DbContext
{
public PersonsContext()
: base("name=PersonsContext")
{
} public DbSet<Person> 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<Person>("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文件夹下添加一个控制器,如下:

在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<Person>("Persons");
config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
*/
public class PersonsController : ODataController
{
private PersonsContext db = new PersonsContext(); // GET: odata/Persons
[EnableQuery]
public IQueryable<Person> GetPersons()
{
return db.Persons;
} // GET: odata/Persons(5)
[EnableQuery]
public SingleResult<Person> 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<Person> 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<Person> 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生成数据库不是本节的重点,所以这里一笔带过。下面是我生成的数据库已经填充的数据:

查询实体集

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

 // GET: odata/Persons
[EnableQuery]
public IQueryable<Person> GetPersons()
{
return db.Persons;
} // GET: odata/Persons(5)
[EnableQuery]
public SingleResult<Person> 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)修改查询。

操作演示

新增实体

允许客户端将一个新的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的劣势在于客户端必须发送实体的所有属性,包括没有改变的值。

OData说明书陈述了PATCH是首选。

下面是生成的代码:

// PATCH: odata/Persons(5)
[AcceptVerbs("PATCH", "MERGE")]
public IHttpActionResult Patch([FromODataUri] int key, Delta<Person> 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);
}

使用ASP.NET Web API 2创建OData v4 终结点的更多相关文章

  1. [转]使用ASP.NET Web API 2创建OData v4 终结点

    本文转自:http://www.cnblogs.com/farb/p/ODataAspNetWebAPI.html 开放数据协议(Open Data Protocol[简称OData])是用于Web的 ...

  2. ASP.NET Web API中使用OData

    在ASP.NET Web API中使用OData 一.什么是ODataOData是一个开放的数据协议(Open Data Protocol)在ASP.NET Web API中,对于CRUD(creat ...

  3. ASP.NET Web API 过滤器创建、执行过程(二)

    ASP.NET Web API 过滤器创建.执行过程(二) 前言 前面一篇中讲解了过滤器执行之前的创建,通过实现IFilterProvider注册到当前的HttpConfiguration里的服务容器 ...

  4. ASP.NET Web API 过滤器创建、执行过程(一)

    ASP.NET Web API 过滤器创建.执行过程(一) 前言 在上一篇中我们讲到控制器的执行过程系列,这个系列要搁置一段时间了,因为在控制器执行的过程中包含的信息都是要单独的用一个系列来描述的,就 ...

  5. ASP.NET Web API 控制器创建过程(二)

    ASP.NET Web API 控制器创建过程(二) 前言 本来这篇随笔应该是在上周就该写出来发布的,由于身体跟不上节奏感冒发烧有心无力,这种天气感冒发烧生不如死,也真正的体会到了什么叫病来如山倒,病 ...

  6. ASP.NET Web API 控制器创建过程(一)

    ASP.NET Web API 控制器创建过程(一) 前言 在前面对管道.路由有了基础的了解过后,本篇将带大家一起学习一下在ASP.NET Web API中控制器的创建过程,这过程分为几个部分下面的内 ...

  7. 在ASP.NET Web API中使用OData

    http://www.alixixi.com/program/a/2015063094986.shtml 一.什么是ODataOData是一个开放的数据协议(Open Data Protocol)在A ...

  8. Asp.Net Web API 2第十七课——Creating an OData Endpoint in ASP.NET Web API 2(OData终结点)

    前言 很久没更新博客了,加上刚过年,现在准备重新开战,继续自己的学习之路.本文已同步到Web API2系列文章中http://www.cnblogs.com/aehyok/p/3446289.html ...

  9. 在ASP.NET Web API中使用OData的Action和Function

    本篇体验OData的Action和Function功能.上下文信息参考"ASP.NET Web API基于OData的增删改查,以及处理实体间关系".在本文之前,我存在的疑惑包括: ...

随机推荐

  1. Servlet过滤器(详询请加qq:2085920154)

    1.1  过滤器简介 过滤器是向Web应用程序的请求和响应处理添加功能的Web服务组件.在Servlet处理用户输入的请求之前,过滤器可以访问该请求.在将Web响应发送给用户之前,过滤器还可以访问该响 ...

  2. MVC中的常见问题

    1.  The model backing the 'MusicStoreDBContext' context has changed since the database was created. ...

  3. mac端的优秀抓包工具——Charles使用

    http://my.oschina.net/u/2340880/blog/508688 mac端的优秀抓包工具——Charles使用 一.简介 二.安装与使用 三.使用Charles在mac上进行抓包 ...

  4. Q_OBJECT

    所有QObject的派生类在官方文档中都推荐在头文件中放置宏Q_OBJECT,那么该宏到底为我们做了哪些工作?在qobjectdef.h中有下面的代码: #define Q_OBJECT \ publ ...

  5. jxl 处理 Excel 样式

    jxl 能够操作的 excel 样式: 1. Workbook的格式设置(代表一个excel文件) 2. Sheet的格式设置(代表一个表格) 3. Cell的格式设置(代表一个单元格) PS:此jx ...

  6. php mysql支持emoji表情方案

    将emoji转换成utf8 然后存储到数据库,但是 效率低 public function rrr($text) { $text = 'a

  7. LoopBackJS 之 文件上传下载——使用loopback-component-storage

    参考链接: http://loopback.io/doc/en/lb2/Storage-component.html#creating-a-storage-component-data-source ...

  8. 12个Linux进程管理命令介绍(转)

    12个Linux进程管理命令介绍 [日期:2015-06-02] 来源:Linux中国  作者:Linux [字体:大 中 小]   执行中的程序在称作进程.当程序以可执行文件存放在存储中,并且运行的 ...

  9. JDBC小工具--TxQueryRunner及其单元测试

    1.TxQueryRunner的简介(需要相关jar包的请留言) TxQueryRunner类是common-dbutils下QueryRunner的子类,是用来简化JDBC操作的,所以要导入comm ...

  10. 快手 KSCAD 5.0 矢量图形设计软件

    今天我的快手软件发布了一个最新版本 KSCAD 5.0,免费使用, 详情请看 www.timegis.com 快手 5.0 (KSCAD) 是一款简单易用的矢量绘图软件,其功能和Visio类似,可以绘 ...