zoukankan      html  css  js  c++  java
  • [水煮 ASP.NET Web API2 方法论](12-4)OData 支持的 Function 和 Action

    问题

    在 Web API 中使用 OData Function 和 Action。

     

    解决方案

    可以通过 ODataModelBuilder,使用 OData 构建 ASP.NET Web API, EntityCollectionConfiguration,EnityTypeConfiguration 类中提供的一系列 Function 和 Action 来自定义 Function 和 Action。

    当我们都建自己的 ODataModelBuilder 的时候,可以指定 Function 或 Action 名称并定义他们的输入参数。如清单12-12 所示。

    清单 12-12. 

     1             var ODataBuilder = new ODataConventionModelBuilder();
     2 
     3             ODataBuilder.EntitySet<Player>("Players");
     4 
     5             var player = ODataBuilder.EntityType<Player>();
     6 
     7             // Function – 读取数据
     8 
     9             player.Function("PercentageOfAllGoals").Returns<double>();
    10 
    11             // Action – 请求操作
    12 
    13             player.Action("TradePlayer").Parameter<string>("NewTeam");

    Controller Action 和 OData Function/Action 之间是通过命名的约定建立关联,因此,我们需要在 OData 的 controller 中添加合适的 Action。

     

    工作原理

    ASP.NET WEB API 从 2.2 版本开始支持 OData,而且,已经成为 OData 3.0 规范的一部分。另一方面,在之前 Web API 中 OData 的 Action 也是可以使用的。

    我们是可以以 Web API Action 的形式定义 OData Function/Action 同时暴露给客户端访问。

    使用 Action 或 Function 的主要优势是,我们可以将查询的责任转交给服务器,尤其是复杂查询的时候,可以减轻客户端的不必要的麻烦。

    OData 的 Action 和 Function 是有点不一样的;他们都是在规范中被定义的“一组可以被执或可以作为服务或可以作为资源的操作的扩展”。主要的不同是

    • Function:可以能没有什么结果,但是必须有返回值
    • Action:可以对服务器产生影响,但是不能有返回值
    • 另外,Function 可以在 $filter 中被调用

    在实现了 OData 的 ASP.NET WEB API 中,Action 和 Function 是连同 OData 约定一起被定义,他们是通过 ODataConventionModelBuilder 的实例定义。WEB API OData 的构建支持三种类型(级别)的操作:

    • 服务 Action/Function:ODataModelBuilder 直接定义
    • 集合 Action/Function:EntityCollectionConfiguration 直接定义
    • 实体 Action/Function:EntityTypeConfiguration直接定义

     

    代码演示

     

    如清单 12-13 所示,一个简单的数据集合,为了演示的方面,在 Controller 中通过内存进行数据的操作,还有一个 Player 的 DTO 的类。

    我们就使用这些代码模拟 OData 的三种类型:服务,集合,实体绑定。演示中主要关注在 Function 上,但是, Action 的定义和使用也是几乎一样的。也就是说,在所有使用 Function 声明的方法的地方,都换成 Action 声明的方法是没有毛病的。

     

    清单 12-13. 内存数据和实体模型

     1     public class Player
     2     {
     3         public int Id { get; set; }
     4 
     5         public string Name { get; set; }
     6 
     7         public string Team { get; set; }
     8 
     9         public SkaterStat Stats { get; set; }
    10     }
    11 
    12     public class SkaterStat
    13     {
    14         public int Goals { get; set; }
    15 
    16         public int Assists { get; set; }
    17 
    18         public int GamesPlayed { get; set; }
    19     }
    20 
    21     public class PlayersController : ODataController
    22     {
    23         private static List<Player> _players = new List<Player>
    24         {
    25             new Player
    26             {
    27                 Id = 1,
    28                 Name = "Filip",
    29                 Team = "Whales",
    30                 Stats = new SkaterStat
    31                 {
    32                     GamesPlayed = 82,
    33                     Goals = 37,
    34                     Assists = 43
    35                 }
    36             },
    37             new Player
    38             {
    39                 Id = 2,
    40                 Name = "Felix",
    41                 Team = "Whales",
    42                 Stats = new SkaterStat
    43                 {
    44                     GamesPlayed = 80,
    45                     Goals = 30,
    46                     Assists = 31
    47                 }
    48             new Player
    49 {
    50     Id        = 3,
    51                 Name = "Luiz",
    52                 Team = "Dolphins",
    53                 Stats = new SkaterStat
    54                 {
    55                     GamesPlayed = 78,
    56                     Goals = 20,
    57                     Assists = 30
    58                 }
    59             },
    60             new Player
    61             {
    62                 Id = 4,
    63                 Name = "Terry",
    64                 Team = "Dolphins",
    65                 Stats = new SkaterStat
    66                 {
    67                     GamesPlayed = 58,
    68                     Goals = 19,
    69                     Assists = 30
    70                 }
    71             }
    72         };
    73     }

    前面提到的 Function 方法,来自于 ODataModelBuilder;EntityCollectionConfiguration,EntityTypeConfiguration,都返回一个 FunctionConfiguration 的实例,我们就是用它来配置我们的 Function,例如,在 $filter 中是否支持 Function,接收什么样的参数,应该返回什么。例如,这个演示的 Startup 类中定义了 ODataModelBuilder的 三个 OData  Function 类型和一个实体类型,如清单 12-14 所示。

     

    清单 12-14 OData Function 服务、集合、实体

     1     public class Startup
     2     {
     3 
     4         public void Configuration(IAppBuilder builder)
     5         {
     6 
     7             var ODataBuilder = new ODataConventionModelBuilder();
     8 
     9             ODataBuilder.EntitySet<Player>("Players");
    10 
    11             var player = ODataBuilder.EntityType<Player>();
    12 
    13             /* 集合 Function */
    14 
    15             player.Collection.Function("TopPpg").ReturnsCollection<Player>();
    16 
    17             /* 实体 Function */
    18 
    19             player.Function("PercentageOfAllGoals").Returns<double>();
    20 
    21             /* 服务 Function */
    22 
    23             var serviceFunc = ODataBuilder.Function("TotalTeamPoints");
    24 
    25             serviceFunc.Returns<int>().Parameter<string>("team");
    26 
    27             serviceFunc.IncludeInServiceDocument = true;
    28 
    29             var edm = ODataBuilder.GetEdmModel();
    30 
    31             var config = new HttpConfiguration();
    32 
    33             config.MapODataServiceRoute("Default OData", "OData", edm);
    34 
    35             builder.UseWebApi(config);
    36 
    37         }
    38 
    39     }

    TopPpg 是一个集合 Function,他将返回每场比赛最高分(得分+助攻)比例 player 的集合。PercentageOfAllGoals 是一个实体 Function,返回每场比赛给定参赛者相对所有得分的分数比例。这个 Function 需要客户端传一个 key(player ID),但是,需要注意的是,这个 key 是实体对象的 Id,不需要在 Function 中特殊指明。最后,TotalTeamPoints 是无限制的服务 Function,也就是说,不是特指某一个 player,而是传入一个队名最为参数,同时返回整个队内所有队员分数(得分+助攻)的总和。另外,TotalTeamPoints 也会包含在文档服务中,/OData/$metadata ,作为 Function 入口。

    这些 Function 在 Action 中都是使用的 LINQ 表达式。无限制服务的 Function 使用了 ODataRoute 属性,因为默认的 EMD 驱动路由约定不能完成整个功能。

     

    12-15/ 使用 OData Function 来暴露 Controller 的 Action

     1         [HttpGet]
     2         public IEnumerable<Player> TopPpg()
     3         {
     4             var result = _players.OrderByDescending(x => (double)(x.Stats.Goals + x.Stats.Assists) / (double)x.Stats.GamesPlayed).Take(3);
     5             return (result);
     6         }
     7 
     8 
     9         [HttpGet]
    10         public IHttpActionResult PercentageOfAllGoals(int key)
    11         {
    12             var player = _players.FirstOrDefault(x => x.Id == key);
    13             if (player == null)
    14                 return (NotFound());
    15             var result = (double)player.Stats.Goals / (double)_players.Sum(x => x.Stats.Goals) * 100;
    16             return (Ok(result));
    17         }
    18 
    19 
    20         [HttpGet]
    21         [ODataRoute("TotalTeamPoints(team={team})")]
    22         public int TotalTeamPoints([FromODataUri] string team)
    23         {
    24             var result = _players.Where(x => string.Equals(x.Team, team, StringComparison.
    25                                      InvariantCultureIgnoreCase))
    26                      .Sum(x => x.Stats.Goals + x.Stats.Assists);
    27             return (result);
    28         }

    在这些地方,可以在 URI 中使用 Function 名称来调用他们。根据规范,调用 OData Function 的时候需要使用括号:

    • /OData/Players/Default.TopPpg()
    • /OData/Players(1)/Default.PercentageOfAllGoals()
    • /OData/TotalTeamPoints(team='Whales')

     关于 OData 在 ASP.NET WEB API 中的介绍就此告一段落,接下来,一段时间将介绍关于 Route 的东西。

  • 相关阅读:
    docker简单入门之使用docker容器部署简单的java web开源项目jpress博客程序
    go语言的安装、环境变量配置及简单使用
    bootstrap4简单使用和入门02-bootstrap的js组件简单使用
    bootstrap4简单使用和入门01-简单表单的使用
    bootstrap4简单使用和入门03-响应式布局
    python操作三大主流数据库(14)python操作redis之新闻项目实战②新闻数据的展示及修改、删除操作
    python操作三大主流数据库(13)python操作redis之新闻项目实战①新闻数据的导入
    python操作三大主流数据库(12)python操作redis的api框架redis-py简单使用
    python操作三大主流数据库(11)redis的安装和简单使用
    python操作三大主流数据库(10)python操作mongodb数据库④mongodb新闻项目实战
  • 原文地址:https://www.cnblogs.com/shuizhucode/p/6092305.html
Copyright © 2011-2022 走看看