標簽:開發 權限 動態 alt 微服務 ati 方式 base code
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 }
上述代碼是在 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 能做什么?
我們在 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 的路徑進行分類,甚至在模塊化、插件化的框架下,同一個功能模塊可能會由不同的程序集(或 dll)來支持,這時候怎么讓不同“產地”的 API 進行充分“重組”呢?
我們只需要對 API 進行分類(Category)參數的設置,例如,在上述 ApiBind 特性中添加參數:
![]() |
![]() |
特性標簽添加 Category 參數 | 成功合并到 WeatherForecast 分類 |
上述路徑默認包含(暴露)了 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 支持所有的特性標簽。
除了在某個具體的方法上添加 [ApiBind] 特性標簽,您還可以在類(class)上使用此特性,使下屬所有的方法(包括靜態方法)都擁有相同的配置。
class 上的特性標簽同樣會自動配置,其規則如下:
測試:
將之前的 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 的配置)。
運行結果:
運行結果中:
有時,雖然我們偷懶將某個 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):
|
![]() |
忽略前 | 忽略后 |
請關注后續內容:
https://github.com/JeffreySu/WebApiEngineSample
[本系列未完待續,持續更新中]
動態 WebApi 引擎使用教程(3行代碼完成動態 WebApi 構建)
標簽:開發 權限 動態 alt 微服務 ati 方式 base code
原文地址:https://www.cnblogs.com/szw/p/WebApiEngine.html