ASP.NET Core 奇淫技巧之動態WebApi


一.前言

接觸到動態WebApi(Dynamic Web API)這個詞的已有幾年,是從ABP框架里面接觸到的,當時便對ABP的這個技術很好奇,后面分析了一波,也嘗試過從ABP剝離一個出來作為獨立組件來使用,可是后來因與ABP依賴太多而放棄。十幾天前朋友 熊貓 將這部分代碼(我和他在搞事情)成功的從 ABP 中剝離出來並做了一個簡單Demo扔給我,經過這么久(實在是太懶_)終於經過一些修改、添加功能、封裝,現在已經能作為一個獨立組件使用,項目開源在Github(https://github.com/dotnetauth/Panda.DynamicWebApi),希望覺得有用的朋友能給一個 Star 支持一下。

本文只講使用,不講原理,原理放到后面的文章中詳細介紹。

二.介紹

不管是傳統的三層架構、 DDD 經典四層架構(DDD Lite),亦或是其他具有應用邏輯層(業務邏輯層)的架構,在Web應用程序開發當中 ,我們的業務邏輯最終都需要經過 Web Api 來進行調用,這里我們可能會有一個重復的操作:編寫業務邏輯->編寫API調用業務邏輯,這種重復性的操作有沒有解決辦法呢,我們編寫完業務邏輯以后便給我們自動生成WebApi,答案當然是有的。

這里介紹一下本文的主角:Panda.DynamicWebApihttps://github.com/dotnetauth/Panda.DynamicWebApi)。源自於ABP的一個可獨立使用的,可自動為你的業務邏輯層生成 ASP.NET Core WebApi 層的開源組件。它生成的API符合Restful風格,可以根據符合條件的類來生成WebApi,由MVC框架直接調用邏輯,無性能問題,完美兼容Swagger來構建API說明文檔。

三.使用

這里以 DDD 經典四層架構中的應用邏輯層來講解。

1.准備

(1)建立兩個項目一個是應用邏輯層類庫項目;一個是作為生成WebApi Host,ASP.NET Core WebApi項目

1560273021487

(2)編寫應用邏輯

定義一個應用邏輯接口,所有應用邏輯都應實現它:

public interface IApplicationService
{
}

定義一個學生管理邏輯接口,繼承應用邏輯接口

public interface IStudentAppService : IApplicationService
{
    /// <summary>
    /// 根據ID獲取學生
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    StudentOutput Get(int id);

    /// <summary>
    /// 獲取所有學生
    /// </summary>
    /// <returns></returns>
    List<StudentOutput> Get();

    /// <summary>
    /// 更新學生信息
    /// </summary>
    /// <param name="input"></param>
    void Update(UpdateStudentInput input);

    /// <summary>
    /// 更新學生年齡
    /// </summary>
    /// <param name="age"></param>
    void UpdateAge(int age);

    /// <summary>
    /// 根據ID刪除學生
    /// </summary>
    /// <param name="id"></param>
    void Delete(int id);

    /// <summary>
    /// 添加學生
    /// </summary>
    /// <param name="input"></param>
    void Create(CreateStudentInput input);
}

實現學生邏輯管理接口:

public class StudentAppService: IStudentAppService
{
    /// <summary>
    /// 根據ID獲取學生
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("{id:int}")]
    public StudentOutput Get(int id)
    {
        return new StudentOutput() {Id = 1, Age = 18, Name = "張三"};
    }

    /// <summary>
    /// 獲取所有學生
    /// </summary>
    /// <returns></returns>
    public List<StudentOutput> Get()
    {
        return new List<StudentOutput>()
        {
            new StudentOutput(){Id = 1,Age = 18,Name = "張三"},
            new StudentOutput(){Id = 2,Age = 19,Name = "李四"}
        };
    }

    /// <summary>
    /// 更新學生信息
    /// </summary>
    /// <param name="input"></param>
    public void Update(UpdateStudentInput input)
    {
        throw new System.NotImplementedException();
    }

    /// <summary>
    /// 更新學生年齡
    /// </summary>
    /// <param name="age"></param>
    [HttpPatch("{id:int}/age")]
    public void UpdateAge(int age)
    {
        throw new System.NotImplementedException();
    }

    /// <summary>
    /// 根據ID刪除學生
    /// </summary>
    /// <param name="id"></param>
    [HttpDelete("{id:int}")]
    public void Delete(int id)
    {
        throw new System.NotImplementedException();
    }

    /// <summary>
    /// 添加學生
    /// </summary>
    /// <param name="input"></param>
    public void Create(CreateStudentInput input)
    {
        throw new System.NotImplementedException();
    }
}

(3)給 WebApi Host 項目配置 Swagger。

Install-Package Swashbuckle.AspNetCore -Version 4.0.1

Startup 中配置

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddSwaggerGen(options =>
    {
        options.SwaggerDoc("v1", new Info { Title = "曉晨學生管理系統 WebApi", Version = "v1" });

        options.DocInclusionPredicate((docName, description) => true);

        options.IncludeXmlComments(@"bin\Debug\netcoreapp2.2\Xc.StuMgr.WebApiHost.xml");
        options.IncludeXmlComments(@"bin\Debug\netcoreapp2.2\Xc.StuMgr.Application.xml");
    });
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "曉晨學生管理系統 WebApi");
    });

    app.UseMvc();
}

運行則會直接看到默認的 ValuesController 的5個API。

2.動態WebApi

通過Nuget 為 Application 項目安裝組件:

Install-Package Panda.DynamicWebApi

為接口 IApplicationService繼承 IDynamicWebApi同時添加特性DynamicWebApi

[DynamicWebApi]
public interface IApplicationService:IDynamicWebApi
{
}

在 WebApi Host 項目中,Startup里配置動態WebApi:

Startup.cs:

// 添加動態WebApi 需放在 AddMvc 之后
services.AddDynamicWebApi();

然后打開瀏覽器訪問將會看到:

1560277564506

可以看到成功為我們的 StudentAppService 生成了WebApi,並且和Swagger完美兼容。

四.詳細介紹

經過上面的介紹,大家應該可以看出使用是非常簡單的,只需兩步:

第一步:為你的類(或者該類的接口、該類繼承的抽象類,不得放在該類前面兩種情況的父類上)繼承 IDynamicWebApi接口並加入特性[DynamicWebApi]

第二步:Startup中注冊

// 添加動態WebApi 需放在 AddMvc 之后
services.AddDynamicWebApi();

因為需要MVC的一些類來進行處理,所以必須放在AddMvc之后,本組件有檢查。

1.規則

本組件采用約定大於配置,所以在實際使用中有幾個規則:

(1)要讓類生成動態API需要滿足兩個條件,一個是該類直接間接實現 IDynamicWebApi,同時該類本身或者父抽象類或者實現的接口具有特性 DynamicWebApi

(2)添加特性 [NonDynamicWebApi] 可使一個類或者一個方法不生成API,[NonDynamicWebApi] 具有最高的優先級。

(3)會對符合規則的動態API類名進行后綴的刪除,如:我們前面的 StudentAppService,會被刪除 AppService 后綴,這個規則是可以動態配置的。

(4)會自動添加API路由前綴,默認會為所有API添加 api前綴

(5)默認的HTTP動詞為POST,可以通過 HttpGet/HttpPost/HttpDelete 等等ASP.NET Core 內置特性來覆蓋

(6)可以通過HttpGet/HttpPost/HttpDelete 等內置特性來覆蓋默認路由

(7)默認會根據你的方法名字來設置HTTP動詞,如 CreateApple 或者 Create 生成的API動詞為 POST,對照表如下,若命中(忽略大小寫)對照表那么該API的名稱中的這個動詞將會被省略,如 CreateApple 將會變成 Apple,如未在以下對照表中,將會使用默認動詞 POST

方法名開頭 動詞
create POST
add POST
post POST
get GET
find GET
fetch GET
query GET
update PUT
put PUT
delete DELETE
remove DELETE

(8)強烈建議方法名稱使用帕斯卡命名(PascalCase)規范,以更好的自動處理API名稱,且使用以上對照表的動詞。如:

添加蘋果 -> Add/AddApple/Create/CreateApple

更新蘋果 -> Update/UpdateApple

...

(9)[DynamicWebApi] 特性因為可被繼承,所以為了父類被誤識別,禁止放在除抽象類、接口以外的父類上。

2.配置

所有的配置均在對象 DynamicWebApiOptions 中,說明如下:

屬性名 是否必須 說明
DefaultHttpVerb 默認值:POST。默認HTTP動詞
DefaultAreaName 默認值:空。Area 路由名稱
DefaultApiPrefix 默認值:api。API路由前綴
RemoveControllerPostfixes 默認值:AppService/ApplicationService。類名需要移除的后綴
RemoveActionPostfixes 默認值:Async。方法名需要移除的后綴
FormBodyBindingIgnoredTypes 默認值:IFormFile。不通過MVC綁定到參數列表的類型。

五.疑難解答

若遇到問題,可使用 Issues 進行提問。

六.結束

本項目開源地址:https://github.com/dotnetauth/Panda.DynamicWebApi 希望給個 Star 支持一下

本文Demo地址:XiaoChen.StudentManagement

ABP:https://github.com/aspnetboilerplate/aspnetboilerplate


免責聲明!

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



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