ASP.NET Web API 2 OData v4教程

时间:2021-01-20 15:22:41
程序数据库格式标准化的开源数据协议
为了增强各种网页应用程序之间的数据兼容性,微软公司启动了一项旨在推广网页程序数据库格式标准化的开源数据协议(OData)计划,于此同时,他们还发 布了一款适用于OData协议的开发工具,以方便网页程序开发者们使用。
Open Data Protocol (开放数据协议,OData)是用来查询和更新数据的一种Web协议,其提供了把存在于应用程序中的数据暴露出来的方式。OData运用且构建于很多 Web技术之上,比如HTTP、Atom Publishing Protocol(AtomPub)和JSON,提供了从各种应用程序、服务和存储库中访问信息的能力。OData被用来从各种数据源中暴露和访问信息, 这些数据源包括但不限于:关系数据库、文件系统、内容管理系统和传统Web站点。

创建项目

在VS中创建一个新的Asp.Net Web应用项目,命名为“PersonsService”,如下图:ASP.NET Web API 2 OData v4教程

ASP.NET Web API 2 OData v4教程

安装Nuet包

ASP.NET Web API 2 OData v4教程

搜索Microsoft.AspNet.Odata包跟EntityFramework包安装

ASP.NET Web API 2 OData v4教程

ASP.NET Web API 2 OData v4教程

添加Model类

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; }
    }
}  

 生成数据库

打开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; }
    }
}

 打开NuGet包管理器,程序包管理器控制台输入以下命令  "enable-migrations" ,"add-migration","update-database "

ASP.NET Web API 2 OData v4教程

这个时候打开SQL Server 就可以看到已经创建好的数据库

ASP.NET Web API 2 OData v4教程

配置OData终结点

打开App_Start/WebApiConfig.cs文件,配置下面的新代码

using Microsoft.OData.Edm;
using PersonsService.Models;
using System.Web.Http;
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
namespace PersonsService
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服务
            // Web API 路由
            config.MapHttpAttributeRoutes();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
            //构建路由服务
            config.MapODataServiceRoute(
                routeName: "odata",
                routePrefix: "odata",
                model: GetModel()
                );
        }
        private static IEdmModel GetModel()
        {
            var builder = new ODataConventionModelBuilder();
            var esPerson = builder.EntitySet<Person>("Persons");
            return 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文件夹下添加一个控制器,如下:

 

ASP.NET Web API 2 OData v4教程

 

 

修改控制器代码,如下:

using PersonsService.Models;
using System.Linq;
using System.Web.OData;
namespace PersonsService.Controllers
{
    public class PersonsController : ODataController
    {
        private readonly PersonsContext db = new PersonsContext();
        [EnableQuery]
        public IQueryable<Person> Get()
        {
            return db.Persons;
        }
        [EnableQuery]
        public IQueryable<Person> Get([FromODataUri] int key)
        {
            return db.Persons.Where(r=> r.Id==key);
        }
    }
}

  这时我们手动给数据库添加些数据,

ASP.NET Web API 2 OData v4教程

好了,现在我们运行项目尝试请求下

请求http://localhost:3370/odata/Persons

ASP.NET Web API 2 OData v4教程

现在数据都出来了,试下请求单个Person

http://localhost:3370/odata/Persons(1)

ASP.NET Web API 2 OData v4教程

一切正常

无参数的Get()方法会返回整个Person表的集合。
Get([FromODataUri] int key)方法会返回指定Id的Person。

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

添加一个Post方法来添加Person

        [HttpPost]
        public IHttpActionResult Post(Person person)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            db.Persons.Add(person);
            db.SaveChanges();
            return Created(person);
        }

 使用post请求http://localhost:3370/odata/Persons

ASP.NET Web API 2 OData v4教程

看下数据库赵六已经添加进去了,现在添加一个修改方法

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

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

PUT的劣势在于客户端必须发送实体的所有属性,包括没有改变的值。
OData说明书陈述了PATCH是首选。

        [AcceptVerbs("PATCH", "MERGE")]
        public IHttpActionResult Patch([FromODataUri] int key, Delta<Person> patch)
        {
            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)
            {
                    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);
        }

  后续会补充下odata配置自定义路由的问题.

Odata 自定义路由

        [EnableQuery, HttpGet]
        [ODataRoute("Products({id})/Default.GetCatAndTown")]
        public IHttpActionResult GetCatAndTown([FromODataUri] int id)
        {
            var list = db.Products.Where(r => r.Id == id);
            return Ok(list);
        }

  当然这个时候我们请求http://localhost:6785//Odata/Products(1)/Default.GetCatAndTown会报错404,解决方案是添加一个尾部的斜杠到请求的网址

这个时候我们http://localhost:6785//Odata/Products(1)/Default.GetCatAndTown/就会好了,具体原因不详。或者是修改web.config文件

  <system.webServer>
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0Custom" path="/odata*" verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
  </system.webServer>