動態 WebApi 引擎使用教程(3行代碼完成動態 WebApi 構建)


目錄

 

什么是 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 項目

 

  或使用命令行,免去創建項目的其他步驟:

dotnet new webapi

命令行創建項目模板

 

  項目創建完成后,已經默認包含了一個模擬氣象數據查詢的接口:

原始項目

 

  小貼士:您可以使用 NET Core 3.1 或 .NET 5、.NET 6 進行開發,代碼沒有任何差別。

   運行后默認已經加載了 Swagger:

原始運行頁面,為 Swagger 首頁

  

   使用 Swagger 我們已經可以測試 API:

使用 Swagger 測試接口運行

 

   此處的 API 還是需要手寫 API 才能完成,打開 WeatherForecastController.cs 可以看到初始化內容:

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

    上述代碼是在 Controller 里面直接演示了邏輯代碼(包括數據查詢),更多的情況,我們會把這些邏輯封裝在 Service 中,並由 Controller 調用。如,創建 WeatherService.cs:

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

 

   修改 WeatherForecastController.cs:

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

  

  注意:如果像上述代碼 12 行中那樣,使用構造函數注入 WeatherService,需要在 Startup.cs 中添加:

services.AddScoped<WeatherService>();

 

  當我們在粒度越來越小的微服務、前后端分離的場景下進行開發和迭代,會發現 API 的數量會幾何級數地上升。

  此時為了能讓 Service 中的邏輯方法毫無變化地傳遞給客戶端,需要做大量 API 創建的重復勞動,維護也會越來越混亂。

 越來越復雜、混亂的 API 導致了大量低效、低價值的重復勞動

 

   為了解決這樣的問題,WebApiEngine 登場了! 讓我們來看看 WebApiEngine 能做什么?

 

使用 [ApiBind] 標簽讓任何方法變成 WebApi

  我們在 WeatherService 下再創建一個名為 GetWeatherForecast 的新方法,並附加一個 int 類型參數,用於演示新的接口:

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

   然后,通過簡單的 3 步,完成動態 API 的實現:

 

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

 安裝 Senparc.CO2NET.WebApi 包

 

  也可以在項目目錄下,使用命令行添加:

dotnet add package Senarc.CO2NET.WebApi

     第二步:在 ConfigureServices() 方法中添加兩行代碼:

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

   第三步:添加 [ApiBind] 標簽

  在任意方法上添加 [ApiBind] 標簽,如之前創建的 GetWeatherForecast(int index) 方法:

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

   完成!

 

  重新啟動項目,即可看到新的 GetWeatherForecast 接口:

 
Swagger 首頁,顯示新接口 測試執行

 

    上述我們只添加了 3 行代碼(如果項目本身就需要 services.AddMvcCore(),則只需要 2 行),我們便完成了讓任何一個方法開放為接口的能力!

小貼士

1、您可以試一下靜態方法,同樣有效!

2、細心的開發者已經發現,自動生成的默認請求動作為 Post,我們可以通過修改全局配置修改默認動作,如:

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     public class WeatherService2
2     {
3         [ApiBind("WeatherForecast", "MyApi")]
4         public string GetWeatherForecast(string str)
5         {
6             return "the parameter value is :" + str;
7         }
8     }

運行結果:

 WebApiEngine 會自動處理重名的 API

 

復制特性

  動態 API 的另外一個難點是,正常的 WebAPI 通常都需要定義自己的特性,如訪問鑒權、行為過濾,等等。WebApiEngine可以將原始方法上的特性標簽直接復制到動態 API 上。

  我們在 GetWeatherForecast 方法上添加權限驗證特性:

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

  然后運行接口:

 [Authorize] 標簽生效 

 

  上面的測試可以看到 [Authorize] 標簽已經生效(雖然提示了 Authorize 配置錯誤,是因為我們沒有進行授權配置)。

  WebApiEngine 支持所有的特性標簽。

 

為整個類配置 WebApi

  除了在某個具體的方法上添加 [ApiBind] 特性標簽,您還可以在類(class)上使用此特性,使下屬所有的方法(包括靜態方法)都擁有相同的配置。

  class 上的特性標簽同樣會自動配置,其規則如下:

  1. 如果 class 設置了特性標簽(如 [Authorize]),則下屬所有的方法也將繼承對應特性;
  2. 如果下屬方法具有和 class 一樣的特性標簽,將完全覆蓋 class 的特性設置;
  3. 集成特性標簽的順序,為先按順序添加 class 的標簽,后按順序添加方法的標簽(注此順序為 CustomAttributeData.GetCustomAttributes() 獲得到的順序);

測試:

  將之前的 WeatherService2 類進行重寫:

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

  方式二:設置 ApiBind 特性中的 Ignore 屬性,如:

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

 

忽略某些特定的分類

  通過配置,我們也可以忽略部分特定的分類(Category),在運行引擎之前,在 startup.cs 中進行定義:

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

  只需添加上述第 1 行代碼,即可忽略整個 WeatherForecast 分類的接口(當然不能忽略通過原始方法編寫的 Controller 內的 API):

 
忽略前 忽略后

 

進階

  請關注后續內容:

  • 《1 行代碼,將任何一個方法開放為 WebApi》
  • 《1 行代碼,配置 WebApi 的注釋文檔》
  • 《0 代碼,結合 NeuCharFramework 高效使用 WebApiEngine》
  • 《使用 WebApiEngine 實現微信接口可視化測試環境》
  • 《使用 NeuCharFramework + WebApiEngine 搭建微信全平台接口代理服務器》
  • 等等

 

本文示例源碼下載

https://github.com/JeffreySu/WebApiEngineSample

 

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM