目录

什么是 WebApiEngine?

  WebApiEngine 是一个可用于动态 WebApi 生成的引擎,基于 .NET Core(包括 .NET 5、 .NET 6),用于解决前后端分离、微服务、异步 Web 请求场景下的 WebApi 的动态生成和管理,并全面兼容 Swagger。

开源地址

  WebApiEngine 完全开源,可商用。承载于 Senparc.CO2NET.WebApi 库,同属于 CO2NET 开源项目:

https://github.com/Senparc/Senparc.CO2NET

使用方法

  以下是 WebApiEngine 的使用方法,将以最原始的默认 .NET Core WebApi 模板项目作为基础进行构建,以便大家学习和亲手实践。

  首先,使用 Visual Stduio 或命令行创建原始项目。

选择 ASP.NET Core Web API 项目

  或使用命令行,免去创建项目的其他步骤:

  1. dotnet new webapi

命令行创建项目模板

  项目创建完成后,已经默认包含了一个模拟气象数据查询的接口:

原始项目

小贴士:您可以使用 NET Core 3.1 或 .NET 5、.NET 6 进行开发,代码没有任何差别。

  运行后默认已经加载了 Swagger:

原始运行页面,为 Swagger 首页

  使用 Swagger 我们已经可以测试 API:

使用 Swagger 测试接口运行

  此处的 API 还是需要手写 API 才能完成,打开 WeatherForecastController.cs 可以看到初始化内容:

  1. 1 using Microsoft.AspNetCore.Mvc;
  2. 2 using Microsoft.Extensions.Logging;
  3. 3 using System;
  4. 4 using System.Collections.Generic;
  5. 5 using System.Linq;
  6. 6 using System.Threading.Tasks;
  7. 7
  8. 8 namespace WebApiSample.Controllers
  9. 9 {
  10. 10 [ApiController]
  11. 11 [Route("[controller]")]
  12. 12 public class WeatherForecastController : ControllerBase
  13. 13 {
  14. 14 private static readonly string[] Summaries = new[]
  15. 15 {
  16. 16 "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
  17. 17 };
  18. 18
  19. 19 private readonly ILogger<WeatherForecastController> _logger;
  20. 20
  21. 21 public WeatherForecastController(ILogger<WeatherForecastController> logger)
  22. 22 {
  23. 23 _logger = logger;
  24. 24 }
  25. 25
  26. 26 [HttpGet]
  27. 27 public IEnumerable<WeatherForecast> Get()
  28. 28 {
  29. 29 var rng = new Random();
  30. 30 return Enumerable.Range(1, 5).Select(index => new WeatherForecast
  31. 31 {
  32. 32 Date = DateTime.Now.AddDays(index),
  33. 33 TemperatureC = rng.Next(-20, 55),
  34. 34 Summary = Summaries[rng.Next(Summaries.Length)]
  35. 35 }).ToArray();
  36. 36 }
  37. 37 }
  38. 38 }

  上述代码是在 Controller 里面直接演示了逻辑代码(包括数据查询),更多的情况,我们会把这些逻辑封装在 Service 中,并由 Controller 调用。如,创建 WeatherService.cs:

  1. 1 using System;
  2. 2 using System.Collections.Generic;
  3. 3 using System.Linq;
  4. 4
  5. 5 namespace WebApiSample
  6. 6 {
  7. 7 public class WeatherService
  8. 8 {
  9. 9 private static readonly string[] Summaries = new[]
  10. 10 {
  11. 11 "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
  12. 12 };
  13. 13
  14. 14 public IEnumerable<WeatherForecast> GetWeatherForecasts()
  15. 15 {
  16. 16 var rng = new Random();
  17. 17 return Enumerable.Range(1, 5).Select(index => new WeatherForecast
  18. 18 {
  19. 19 Date = DateTime.Now.AddDays(index),
  20. 20 TemperatureC = rng.Next(-20, 55),
  21. 21 Summary = Summaries[rng.Next(Summaries.Length)]
  22. 22 })
  23. 23 .ToArray();
  24. 24 }
  25. 25 }
  26. 26 }

  修改 WeatherForecastController.cs:

  1. 1 using Microsoft.AspNetCore.Mvc;
  2. 2 using System.Collections.Generic;
  3. 3
  4. 4 namespace WebApiSample.Controllers
  5. 5 {
  6. 6 [ApiController]
  7. 7 [Route("[controller]")]
  8. 8 public class WeatherForecastController : ControllerBase
  9. 9 {
  10. 10 private readonly WeatherService _weatherService;
  11. 11
  12. 12 public WeatherForecastController(WeatherService weatherService)
  13. 13 {
  14. 14 this._weatherService = weatherService;
  15. 15 }
  16. 16
  17. 17 [HttpGet]
  18. 18 public IEnumerable<WeatherForecast> Get()
  19. 19 {
  20. 20 return _weatherService.GetWeatherForecasts();
  21. 21 }
  22. 22 }
  23. 23 }

  

  注意:如果像上述代码 12 行中那样,使用构造函数注入 WeatherService,需要在 Startup.cs 中添加:

  1. services.AddScoped<WeatherService>();

  当我们在粒度越来越小的微服务、前后端分离的场景下进行开发和迭代,会发现 API 的数量会几何级数地上升。

  此时为了能让 Service 中的逻辑方法毫无变化地传递给客户端,需要做大量 API 创建的重复劳动,维护也会越来越混乱。

越来越复杂、混乱的 API 导致了大量低效、低价值的重复劳动

  为了解决这样的问题,WebApiEngine 登场了! 让我们来看看 WebApiEngine 能做什么?

使用 [ApiBind] 标签让任何方法变成 WebApi

  我们在 WeatherService 下再创建一个名为 GetWeatherForecast 的新方法,并附加一个 int 类型参数,用于演示新的接口:

  1. 1 public WeatherForecast GetWeatherForecast(int index)
  2. 2 {
  3. 3 var rng = new Random();
  4. 4 return new WeatherForecast
  5. 5 {
  6. 6 Date = DateTime.Now.AddDays(index),
  7. 7 TemperatureC = rng.Next(-20, 55),
  8. 8 Summary = Summaries[rng.Next(Summaries.Length)]
  9. 9 };
  10. 10 }

  然后,通过加单的 3 步,完成动态 API 的实现:

  第一步:安装 Senparc.CO2NET.WebApi 包:

安装 Senparc.CO2NET.WebApi 包

  也可以在项目目录下,使用命令行添加:

  1. dotnet add package Senarc.CO2NET.WebApi

   第二步:在 ConfigureServices() 方法中添加两行代码:

  1. 1 var builder = services.AddMvcCore().AddApiExplorer();
  2. 2 services.AddAndInitDynamicApi(builder, null);

  第三步:添加 [ApiBind] 标签

  在任意方法上添加 [ApiBind] 标签,如之前创建的 GetWeatherForecast(int index) 方法:

  1. 1 [ApiBind]
  2. 2 public WeatherForecast GetWeatherForecast(int index)
  3. 3 {
  4. 4 var rng = new Random();
  5. 5 return new WeatherForecast
  6. 6 {
  7. 7 Date = DateTime.Now.AddDays(index),
  8. 8 TemperatureC = rng.Next(-20, 55),
  9. 9 Summary = Summaries[rng.Next(Summaries.Length)]
  10. 10 };
  11. 11 }

  完成!

  重新启动项目,即可看到新的 GetWeatherForecast 接口:

 
Swagger 首页,显示新接口 测试执行

  上述我们只添加了 3 行代码(如果项目本身就需要 services.AddMvcCore(),则只需要 2 行),我们便完成了让任何一个方法开放为接口的能力!

小贴士

1、您可以试一下静态方法,同样有效!

2、细心的开发者已经发现,自动生成的默认请求动作为 Post,我们可以通过修改全局配置修改默认动作,如:

  1. 1 services.AddAndInitDynamicApi(builder, null, ApiRequestMethod.Get);

对 API 进行分类

  有时候,为了方便 API 的管理,我们会对 API 的路径进行分类,甚至在模块化、插件化的框架下,同一个功能模块可能会由不同的程序集(或 dll)来支持,这时候怎么让不同“产地”的 API 进行充分“重组”呢?

  我们只需要对 API 进行分类(Category)参数的设置,例如,在上述 ApiBind 特性中添加参数:

 
特性标签添加 Category 参数 成功合并到 WeatherForecast 分类

自定义 API 名称

  上述路径默认包含(暴露)了 GetWeatherForecast 方法所属的类,有时我们甚至需要将多个不同类下面的方法,整合到同一个路径前缀下,这种情况下,可以继续定义 ApiBind 的 Name 参数,使其拥有自定义的路径前缀:

特性标签设置 Name 参数 配置完全可控的路径前缀

小贴士

为了防止接口名称重合和便于直观定位,接口路径最后一段命名(WeatherForecast_MyApi)目前不可设置,规则为:<类名>_<方法名>。

当然如果真的出现重名,WebApiEngine 也会自动修改。

测试:我们添加一个新的类 WeatherService2,并且标记一个具有相同 Category 和 Name 值的方法:

  1. 1 public class WeatherService2
  2. 2 {
  3. 3 [ApiBind("WeatherForecast", "MyApi")]
  4. 4 public string GetWeatherForecast(string str)
  5. 5 {
  6. 6 return "the parameter value is :" + str;
  7. 7 }
  8. 8 }

运行结果:

WebApiEngine 会自动处理重名的 API

复制特性

  动态 API 的另外一个难点是,正常的 WebAPI 通常都需要定义自己的特性,如访问鉴权、行为过滤,等等。WebApiEngine可以将原始方法上的特性标签直接复制到动态 API 上。

  我们在 GetWeatherForecast 方法上添加权限验证特性:

  1. 1 [ApiBind("WeatherForecast", "MyApi")]
  2. 2 [Authorize]
  3. 3 public WeatherForecast GetWeatherForecast(int index)
  4. 4 {
  5. 5 var rng = new Random();
  6. 6 return new WeatherForecast
  7. 7 {
  8. 8 Date = DateTime.Now.AddDays(index),
  9. 9 TemperatureC = rng.Next(-20, 55),
  10. 10 Summary = Summaries[rng.Next(Summaries.Length)]
  11. 11 };
  12. 12 }

  然后运行接口:

[Authorize] 标签生效

  上面的测试可以看到 [Authorize] 标签已经生效(虽然提示了 Authorize 配置错误,是因为我们没有进行授权配置)。

  WebApiEngine 支持所有的特性标签。

为整个类配置 WebApi

  除了在某个具体的方法上添加 [ApiBind] 特性标签,您还可以在类(class)上使用此特性,使下属所有的方法(包括静态方法)都拥有相同的配置。

  class 上的特性标签同样会自动配置,其规则如下:

  1. 如果 class 设置了特性标签(如 [Authorize]),则下属所有的方法也将继承对应特性;
  2. 如果下属方法具有和 class 一样的特性标签,将完全覆盖 class 的特性设置;
  3. 集成特性标签的顺序,为先按顺序添加 class 的标签,后按顺序添加方法的标签(注此顺序为 CustomAttributeData.GetCustomAttributes() 获得到的顺序);

测试:

  将之前的 WeatherService2 类进行重写:

  1. 1 [ApiBind("ClassCoverAttribute", "MyApi")]
  2. 2 public class WeatherService2
  3. 3 {
  4. 4 public string GetWeatherForecast(string str)
  5. 5 {
  6. 6 return "the parameter value is :" + str;
  7. 7 }
  8. 8
  9. 9 [ApiBind(ApiRequestMethod = ApiRequestMethod.Get)]
  10. 10 public string GetWeatherForecastCopy(string str)
  11. 11 {
  12. 12 return "the parameter value is :" + str;
  13. 13 }
  14. 14
  15. 15 public static string GetWeatherForecastCopyStatic(string str)
  16. 16 {
  17. 17 return "[static method]the parameter value is :" + str;
  18. 18 }
  19. 19 }

  第 1 行代码在 class 上进行添加,使其中 2 个方法都生效。

  第 9 行代码改写了 ApiBind 标签,使默认的 Post 方法,改为了 Get 方法。

  第 10 行代码是一个静态方法,同样能“享受”整个 class 的配置(当然也支持使用自定义 [ApiBind],然后覆盖 class 的配置)。

运行结果:

  运行结果中:

  • ① 是 GetWeatherForecast() 方法
  • ② 是 GetWeatherForecastCopyStatic() 静态方法(因为使用了 class继承,因此默认为相同的名称,后续版本将升级为当前方法名称)
  • ③ 是 WeatherService 类中的演示方法,和当前类无关
  • ④ 是 GetWeatherForecastCopy() 方法,该方法的 [ApiBind] 特性覆盖了 class 上的特性,因此没有指定 Category,使用了默认的分类名称,即当前程序集名称

忽略某些特定的方法

  有时,虽然我们偷懒将某个 class 一次性标记为 [ApiBind],但也会有个别的方法,我们并不希望开放为 API,这时候,可以使用 WebApiEngine 提供的忽略方法。

  有两种方式可以做到。

  方式一:使用 IgnoreApiBind 特性,如:

  1. 1 [IgnoreApiBind]
  2. 2 public static string GetWeatherForecastCopyStatic(string str)
  3. 3 {
  4. 4 return "[static method]the parameter value is :" + str;
  5. 5 }

  方式二:设置 ApiBind 特性中的 Ignore 属性,如:

  1. 1 [ApiBind(Ignore = true)]
  2. 2 public static string GetWeatherForecastCopyStatic(string str)
  3. 3 {
  4. 4 return "[static method]the parameter value is :" + str;
  5. 5 }

忽略某些特定的分类

  通过配置,我们也可以忽略部分特定的分类(Category),在运行引擎之前,在 startup.cs 中进行定义:

  1. 1 Senparc.CO2NET.WebApi.Register.AddOmitCategory("WeatherForecast");
  2. 2
  3. 3 var builder = services.AddMvcCore().AddApiExplorer();
  4. 4 services.AddAndInitDynamicApi(builder, null);

  只需添加上述第 1 行代码,即可忽略整个 WeatherForecast 分类的接口(当然不能忽略通过原始方法编写的 Controller 内的 API):

 
忽略前 忽略后

进阶

  请关注后续内容:

  • 《1 行代码,将任何一个方法开放为 WebApi》
  • 《1 行代码,配置 WebApi 的注释文档》
  • 《0 代码,结合 NeuCharFramework 高效使用 WebApiEngine》
  • 《使用 WebApiEngine 实现微信接口可视化测试环境》
  • 《使用 NeuCharFramework + WebApiEngine 搭建微信全平台接口代理服务器》
  • 等等

本文示例源码下载

https://github.com/JeffreySu/WebApiEngineSample

[本系列未完待续,持续更新中]

动态 WebApi 引擎使用教程(3行代码完成动态 WebApi 构建)的更多相关文章

  1. JavaScript模板引擎原理,几行代码的事儿

    一.前言 什么是模板引擎,说的简单点,就是一个字符串中有几个变量待定.比如: var tpl = 'Hei, my name is <%name%>, and I\'m <%age% ...

  2. Python爬虫教程(16行代码爬百度)

    最近在学习python,不过有一个正则表达式一直搞不懂,自己直接使用最笨的方法写出了一个百度爬虫,只有短短16行代码.首先安装必背包: pip3 install bs4 pip3 install re ...

  3. jQuery动态添加删除与添加表行代码

    具体实现代码如下: table的HTML如下: 代码如下 复制代码 <input type="button" value="添加一行" />< ...

  4. 动态横向(水平)合并Repeater数据行DataItem的列

    Insus.NET有对GridView控件进行横纵分别合并列:横:<动态横向(水平)合并GridView数据行DataRow的列>http://www.cnblogs.com/insus/ ...

  5. JAE京东云引擎Git上传管理代码教程和京东云数据库导入导出管理

    文章目录 Git管理准备工作 Git工具上传代码 发布代码装程序 mywebsql管理 京东云引擎小结   JAE京东云引擎是京东推出的支持Java.Ruby.Python.PHP.Node.js多语 ...

  6. 《zw版·Halcon-delphi系列原创教程》 只有2行代码的超市收款单ocr脚本

    <zw版·Halcon-delphi系列原创教程> 只有2行代码的超市收款单ocr脚本只有2行代码的超市收款单ocr脚本 发了这么多教程,有网友问,为什么没有ocr的.      的确,在 ...

  7. 《zw版·Halcon-delphi系列原创教程》简单的令人发指,只有10行代码的车牌识别脚本

    <zw版·Halcon-delphi系列原创教程>简单的令人发指,只有10行代码的车牌识别脚本 简单的令人发指,只有10行代码的车牌识别脚本      人脸识别.车牌识别是opencv当中 ...

  8. JS模版引擎[20行代码实现模版引擎读后感]

    曾经阅读过<只有20行JAVASCRIPT代码, 手把手教你写一个页面模版引擎>这篇文章, 对其中实现模版的想法实在膜拜, 于是有了这篇读后感, 谈谈自己对模版引擎的理解, 以及用自己的语 ...

  9. 使用PyQt(Python+Qt)+动态编译36行代码实现的计算器

    PyQt是基于跨平台的图形界面C++开发工具Qt加Python包装的一个GPL软件(GPL是GNU General Public License的缩写,是GNU通用公共授权非正式的中文翻译),Qt基于 ...

随机推荐

  1. Linux学习笔记:Linux命令之文件处理命令

    文件处理命令 touch 命令名称:touch 执行权限:所有用户 功能描述:创建空文件 语法:touch [文件名] touch创建文件的时候命名不推荐存在空格,如下面的情况 1touch prog ...

  2. NX二次开发-创建(临时)坐标系

    函数:UF_CSYS_create_csys() . UF_CSYS_create_temp_csys() 函数说明:创建坐标系 .创建临时坐标系 用法: #include <uf.h> ...

  3. python实现机器学习笔记

    #课程链接 https://www.imooc.com/video/20165 一.机器学习介绍以及环境部署 1.机器学习介绍及其原理 1)什么是人工智能 人工智能就其本质而言,是机器对人的思维信息过 ...

  4. vue keep-alive从列表页进入详情页,再返回列表页时,还是之前滚动的位置

    //router.js { path: '/oppo-music', component: () => import('@/views/OppoMusic.vue'), meta: { titl ...

  5. 合宙Luat直播间即将开启,你揭开行业奥秘,让你快人一步。

    嗨~刚陪你们过儿童节 和你们一起成长的合宙Luat 又有新计划 -- 合宙Luat官方直播即将开启 - 敬请关注 - - 官方直播什么内容 - 可能是合宙研发动态 可能是新品发布资讯 可能是行业大咖分 ...

  6. 手写Spring Config,最终一战,来瞅瞅撒!

    上一篇说到了手写Spring AOP,来进行功能的增强,下面本篇内容主要是手写Spring Config.通过配置的方式来使用Spring 前面内容链接: 我自横刀向天笑,手写Spring IOC容器 ...

  7. Map类型的Json格式

    示例代码: Map<String, Object> map = new HashMap<>();// boolean 类型 map.put("boolean" ...

  8. 通过UnityWebRequest得到的纹理转精灵

    private IEnumerator GetImage(string url, Image fileImage) { UnityWebRequest WebRequest = new UnityWe ...

  9. 腾讯云TKE-基于 Cilium 统一混合云容器网络(下)

    前言 在 腾讯云TKE - 基于 Cilium 统一混合云容器网络(上) 中,我们介绍 TKE 混合云的跨平面网络互通方案和 TKE 混合云 Overlay 网络方案.公有云 TKE 集群添加第三方 ...

  10. MySQL原理 - InnoDB引擎 - 行记录存储 - Off-page 列

    本文基于 MySQL 8 在前面的两篇文章,我们分析了 MySQL InnoDB 引擎的两种行记录存储格式: Compact 格式 Redundant 格式 在这里简单总结下: Compact 格式结 ...