zoukankan      html  css  js  c++  java
  • [水煮 ASP.NET Web API2 方法论](12-1)创建 OData

    问题

      怎样用在 Web API 中创建 OData 服务。

    解决方案

      对于我们来说,在 Web API 中使用 OData最简单的方式就是使用 ASP.NET 模板来创建Odata Controller。在 Controllers 文件夹上鼠标右键->添加->新建项。

    wKiom1glDKCzoR0BAAEYtJ6ZIOQ942.png

      显示一个如图 12-1 的对话框,在这里我们可以选择两个 Web API 2 OData 相关的模板。Vistual Studio将会生成相关的 OData Controller,同时,从 NuGet 上下载 OData 需要的所有程序集。

     12-1. 使用模板添加 OData Controller

    wKioL1glDMaxZzIIAAC5fDASuZ4568.png

     

      不过,这个模板仅仅对于 WEB Host ASP.NET Web API 托管在 ASP.NET Web 应用程序中)是可以用。对于 Web API 托管在其他地方,我们可以通过 NuGet 手动安装 OData Microsoft.AspNet.OData 来开启我们的OData 开发之旅。

    工作原理

      OData 是一种通过 HTTP 公开丰富 API的标准化协议。OData 4.0 已经被 OASIS 国际开放标准联盟批准,也被认为是 Web 界的 ODBC

     

    Open Data ProtocolOData )可以创建基于REST 的数据服务,可以是资源,使用 URL 和定义的数据模型,可以通过 Web 客户端使用简单的 HTTP 消息来发布和编辑。

     OData 4.0

    http://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part1-protocol.html

    小提示 OData 主页 www.odata.org 里面有所有感兴趣的资源,他可以帮助我们了解 Odato 协议。

    ASP.NET WWB API 2.2 支持 OData 4.0Microsoft.AspNet.OData NuGet 包),然而,之前的 Web API 支持的OData 3.0。如果我们要是指定引用 Mircosoft.Aspnet.WebApi.OData NuGet ,还是可以使用 OData 3.0

    OData Controller 应该继承自 ODataController 基类,而不是常规的ApiControllerASP.NET Web API 允许我们在一个项目中混合使用 OData Controller  传统的 Controller,所以,我们可以在提供 OData Api 的同时提供常规 Api

    Controller 继承 ODataController 是有框架进行不同配置的。被称为 ODataActionSelector  Odata IHttpAcionSelector 的实现类,是基于 Odata 路由的约定,以及一组特定的媒体类型格式化也是被默认替换的。所有的 OData 格式化程序都是 ODataMediaTypeFormatter 的变种,他可以处理 OData 指定的请求和相应格式,XML  JSON

     

    代码演示

      清单 12-1 展示了一个完成的功能,而且很典型的 ODataController  CRUD。在这样的情况下,会通过ASP.NET 的模板根据 Player 实体和 EF 数据上下文生成 Controller

    清单 12-1 典型的 ODataController

    1
    2
    3
    4
    5
    6
    7
    8
    9
    namespace BoiledCode.WebApi.Recipe.ODataDemo.Models
    {
        public class Player
        {
            public int Id { getset; }
            public string Name { getset; }
            public string Team { getset; }
        }
    }

    wKioL1glDN-jaix-AAAmSQFySzs693.png-wh_50

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    using System.Data.Entity.Infrastructure;
    using System.Linq;
    using System.Net;
    using System.Web.Http;
    using System.Web.OData;
    using BoiledCode.WebApi.Recipe.ODataDemo.Models;
      
    namespace BoiledCode.WebApi.Recipe.ODataDemo.Controllers
    {
        /*
        The WebApiConfig class may require additional changes to add a route for this controller. Merge these statements into the Register method of the WebApiConfig class as applicable. Note that OData URLs are case sensitive.
      
        using System.Web.OData.Builder;
        using System.Web.OData.Extensions;
        using BoiledCode.WebApi.Recipe.ODataDemo.Models;
        ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
        builder.EntitySet<Player>("Players");
        config.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());
        */
      
        public class PlayersController : ODataController
        {
            private readonly ApplicationDbContext db = new ApplicationDbContext();
      
            // GET: odata/Players
            [EnableQuery]
            public IQueryable<Player> GetPlayers()
            {
                return db.Players;
            }
      
            // GET: odata/Players(5)
            [EnableQuery]
            public SingleResult<Player> GetPlayer([FromODataUri] int key)
            {
                return SingleResult.Create(db.Players.Where(player => player.Id == key));
            }
      
            // PUT: odata/Players(5)
            public IHttpActionResult Put([FromODataUri] int key, Delta<Player> patch)
            {
                Validate(patch.GetEntity());
      
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
      
                var player = db.Players.Find(key);
                if (player == null)
                {
                    return NotFound();
                }
      
                patch.Put(player);
      
                try
                {
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!PlayerExists(key))
                    {
                        return NotFound();
                    }
                    throw;
                }
      
                return Updated(player);
            }
      
            // POST: odata/Players
            public IHttpActionResult Post(Player player)
            {
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
      
                db.Players.Add(player);
                db.SaveChanges();
      
                return Created(player);
            }
      
            // PATCH: odata/Players(5)
            [AcceptVerbs("PATCH""MERGE")]
            public IHttpActionResult Patch([FromODataUri] int key, Delta<Player> patch)
            {
                Validate(patch.GetEntity());
      
                if (!ModelState.IsValid)
                {
                    return BadRequest(ModelState);
                }
      
                var player = db.Players.Find(key);
                if (player == null)
                {
                    return NotFound();
                }
      
                patch.Patch(player);
      
                try
                {
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!PlayerExists(key))
                    {
                        return NotFound();
                    }
                    throw;
                }
      
                return Updated(player);
            }
      
            // DELETE: odata/Players(5)
            public IHttpActionResult Delete([FromODataUri] int key)
            {
                var player = db.Players.Find(key);
                if (player == null)
                {
                    return NotFound();
                }
      
                db.Players.Remove(player);
                db.SaveChanges();
      
                return StatusCode(HttpStatusCode.NoContent);
            }
      
            protected override void Dispose(bool disposing)
            {
                if (disposing)
                {
                    db.Dispose();
                }
                base.Dispose(disposing);
            }
      
            private bool PlayerExists(int key)
            {
                return db.Players.Count(e => e.Id == key) > 0;
            }
        }
    }

    这个控制器和正常的 Controller 非常相似,只有几个地方是需要强调

    • OData 查询语法是通过     EnableQueryAttribute 来启用的。我们将在 12-3 来继续讨论。

    • OData 查询语法不仅可以用在集合上也可以用在单个实体上,用在单个实体上的时候,只要实体使用  SingleResult<T> 就可以。关于这个我们也是在 12-3 来详细介绍。

    •  URI 绑定的时候,需要使用     FromODataUriAttribute,而不是传统的 Web API FormUriAttribute

    • OData Controller 一般是允许部分实体的更新。这个例子上,是通过 HTTP  PATCH  Delta<T>来实现部分更新。Delta<T> 是一种特殊的类型,可以用于比较两个实体之间的差异,但是,他仅仅适用于     ODataMediaTypeFormatters 类型。

      很显然,控制器并非万能的。使用 OData 的最小要求就是为OData 创建一个实体数据模型(EDM)和 设置OData 路由。这些最终操作的都是 Web API HttpConfiguration 的实例。如清单 12-2 所示,我们会在下一次(12-2)来介绍 OData 路由。EDM 是用来为我们的服务定义 URI,以及提供语义描述(元数据)。

    清单 12-1. 设置 EDM  OData 路由

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
            public void SettingUpEdmRoyte()
            {
                var config = new HttpConfiguration();
                //配置 Web API
                var builder = new ODataConventionModelBuilder();
                builder.EntitySet<Player>("Players");
                // 第一个参数:路由名称,第二个参数:OData 路由前缀
                // players 资源可以被 /odata/players 访问
                config.MapODataServiceRoute("odata""odata", builder.GetEdmModel());
            }

      这个 ODataConventionModelBuilder 类可以帮我们创建一个 EDM,我们不需要不必担心名称转换,导航属性,主键。如果我们需要自定义这些默认关系,那么,我们就需要使用它的基类 ODataModelBuilder,而不是ODataConventionModelBuilder

      EntitySet方法添加实体并设置为 EDM 同时定义指定的 ODataController 来处理相应资源的 HTTP 请求,在我们的例子中就是 PlayersController

  • 相关阅读:
    Chrome 开发者工具使用技巧
    POJ2485 Highways 【MST】
    Android 之UI自适应解决方式
    自己封装的轮播工具
    usb芯片调试经验
    SQLSEVER 中的那些键和约束
    mysql通过DATE_FORMAT将错误数据恢复
    vim使用(二):经常使用功能
    Linux系列-Xshell连接本地VMware安装的Linux虚拟机
    LeetCode 107 Binary Tree Level Order Traversal II(二叉树的层级顺序遍历2)(*)
  • 原文地址:https://www.cnblogs.com/shuizhucode/p/6076238.html
Copyright © 2011-2022 走看看