[转]使用ASP.NET Web API 2创建OData v4 终结点
本文转自:http://www.cnblogs.com/farb/p/ODataAspNetWebAPI.html
开放数据协议(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 终结点的更多相关文章
- 使用ASP.NET Web API 2创建OData v4 终结点
		
开放数据协议(Open Data Protocol[简称OData])是用于Web的数据访问协议.OData提供了一种对数据集进行CRUD操作(Create,Read,Update,Delete)的统 ...
 - ASP.NET Web API 过滤器创建、执行过程(二)
		
ASP.NET Web API 过滤器创建.执行过程(二) 前言 前面一篇中讲解了过滤器执行之前的创建,通过实现IFilterProvider注册到当前的HttpConfiguration里的服务容器 ...
 - ASP.NET Web API 过滤器创建、执行过程(一)
		
ASP.NET Web API 过滤器创建.执行过程(一) 前言 在上一篇中我们讲到控制器的执行过程系列,这个系列要搁置一段时间了,因为在控制器执行的过程中包含的信息都是要单独的用一个系列来描述的,就 ...
 - ASP.NET Web API 控制器创建过程(二)
		
ASP.NET Web API 控制器创建过程(二) 前言 本来这篇随笔应该是在上周就该写出来发布的,由于身体跟不上节奏感冒发烧有心无力,这种天气感冒发烧生不如死,也真正的体会到了什么叫病来如山倒,病 ...
 - ASP.NET Web API 控制器创建过程(一)
		
ASP.NET Web API 控制器创建过程(一) 前言 在前面对管道.路由有了基础的了解过后,本篇将带大家一起学习一下在ASP.NET Web API中控制器的创建过程,这过程分为几个部分下面的内 ...
 - ASP.NET Web API中使用OData
		
在ASP.NET Web API中使用OData 一.什么是ODataOData是一个开放的数据协议(Open Data Protocol)在ASP.NET Web API中,对于CRUD(creat ...
 - 在ASP.NET Web API中使用OData
		
http://www.alixixi.com/program/a/2015063094986.shtml 一.什么是ODataOData是一个开放的数据协议(Open Data Protocol)在A ...
 - 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 ...
 - 在ASP.NET Web API中使用OData的Action和Function
		
本篇体验OData的Action和Function功能.上下文信息参考"ASP.NET Web API基于OData的增删改查,以及处理实体间关系".在本文之前,我存在的疑惑包括: ...
 
随机推荐
- 浅析c#中==操作符和equals方法
			
在之前的文章中,我们讲到了使用C#中提供的Object类的虚Equals方法来判断Equality,但实际上它还提供了另外一种判断Equality的方法,那就是使用==运算符.许多童鞋也许会想当然的认 ...
 - Let it crash philosophy for distributed systems
			
This past weekend I read Joe Armstrong’s paper on the history of Erlang. Now, HOPL papers in general ...
 - linux 动态库加载路径修改
			
1.在 /etc/ld.so.conf 文件中添加搜索路径,重启或者 ldconfig 生效: 2.在 /etc/ld.so.conf.d 目录下添加 *.conf 文件,其中可以添加搜索路径,重启获 ...
 - 【OCP-12c】CUUG 071题库考试原题及答案解析(21)
			
3.choose three View the Exhibit and examine the description of SALES and PROMOTIONS tables. You want ...
 - BootStrap框架引入文件
			
bootstrap -- 框架 引入需要的 这是外网的------************************************************************* < ...
 - Jmeter非GUI运行,生成html报告
			
一.JMete执行方式 JMeter执行方式有2种,一种是GUI模式,一种是非GUI模式.GUI模式就是界面模式,非GUI模式就是命令行模式.界面模式主要用来编写和调试脚本用的,项目的真正执行最好是采 ...
 - Jquery选择器 选择一个不存在的元素 为什么不会返回 false
			
不管找没找到,$()函数都会返回一个jquery对象,这个jquery对象有个length属性,表示找到多少个匹配的DOM元素,为0就是没找到.
 - 报错 POST http://192.168.79.165:8015/marketing/manager 400 (BAD REQUEST) 解决办法
			
我用jQuery ajax post方法 用flask url_for 传值到后端 $.ajax({ url:"{{url_for('marketing.manager')}}", ...
 - redhat linux elk命令
			
安装es后不能启动原因在elasticsearch.yml中加如下两个配置: bootstrap.memory_lock: falsebootstrap.system_call_filter: fal ...
 - 【性能分析】使用Intel VTune Amplifier
			
本文转自 https://software.intel.com/zh-cn/blogs/2010/11/10/amplxe-cl/版权归原作者所有,如原作者有任何不允许转载之理由,本文将自行删除. I ...