ASP.NET Core 實戰:構建帶有版本控制的 API 介面

来源:https://www.cnblogs.com/danvic712/archive/2018/12/25/10176823.html
-Advertisement-
Play Games

一、前言 在上一篇的文章中,主要是搭建了我們的開發環境,同時創建了我們的項目模板框架。在整個前後端分離的項目中,後端的 API 介面至關重要,它是前端與後端之間進行溝通的媒介,如何構建一個 “好用” 的 API 介面,是需要我們後端人員好好思考的。 在系統迭代的整個過程中,不可避免的會添加新的資源, ...


 一、前言

   在上一篇的文章中,主要是搭建了我們的開發環境,同時創建了我們的項目模板框架。在整個前後端分離的項目中,後端的 API 介面至關重要,它是前端與後端之間進行溝通的媒介,如何構建一個 “好用” 的 API 介面,是需要我們後端人員好好思考的。
  在系統迭代的整個過程中,不可避免的會添加新的資源,或是修改現有的資源,後端介面作為暴露給外界的服務,變動的越小,對服務的使用方造成的印象就越小,因此,如何對我們的 API 介面進行合適的版本控制,我們勢必需要首先考慮。

  系列目錄地址:ASP.NET Core 項目實戰
  倉儲地址:https://github.com/Lanesra712/Grapefruit.VuCore

 二、Step by Step

  項目總是在不斷迭代的,某些時候,因為業務發展的需要,需要將現有的介面進行升級,而原有的介面卻不能立刻停止使用。比如說,你開發了一個介面提供給愛啪啪 1.0 版本使用,後來愛啪啪的版本迭代了,需要介面返回的數據與原先 1.0 版本返回的數據不同了,這時候,介面肯定是需要升級的,可是如果直接升級原有的介面,還在使用 1.0 版本的用戶不就 GG 了,因此,如何做到既可以讓 1.0 版本的用戶使用,也可以讓 2.0 版本的用戶使用就需要好好考慮了,常見的解決方案,主要有以下幾種。

  a)使用不同的 API 名稱

  最簡單粗暴,需要變更介面邏輯時就重新起個 API 名稱,新的版本調用新的 API 名稱,舊的版本調用舊的 API 名稱。

https://yuiter.com/api/Secret/Login ##愛啪啪 1.0
https://yuiter.com/api/Secret/NewLogin ##愛啪啪 2.0

  b)在 Url 中標明版本號

  直接將 API 版本信息添加到請求的 Url 中,調用不同版本的 API ,就在 URL 中直接標明使用的是哪個版本。

https://yuiter.com/api/v1/Secret/Login ##愛啪啪 1.0
https://yuiter.com/api/v2/Secret/Login ##愛啪啪 2.0

  c)請求參數中添加版本信息

  將 API 的版本信息作為請求的一個參數傳遞,通過指定參數值來確定請求的 API 版本。

https://yuiter.com/api/Secret/Login?version=1 ##愛啪啪 1.0
https://yuiter.com/api/Secret/Login?version=2 ##愛啪啪 2.0

  d)在 header 中標明版本號

  前端在請求 API 介面時,在 header 中添加一個參數用來表明請求的版本信息,後端通過前端在 header 中設置的參數來判斷,從而執行不同的業務邏輯分支。

POST https://yuiter.com/api/Secret/Login
Host: yuiter.com  
api-version: v1   ##愛啪啪 1.0

POST https://yuiter.com/api/Secret/Login
Host: yuiter.com  
api-version: v2   ##愛啪啪 2.0

  在 Grapefruit.VuCore 這個項目中,我選擇將 API 的版本信息添加到請求的地址中,從而明確的指出當前請求的介面版本信息。

  1、Swagger 集成

  後端完成了介面之後,肯定需要告訴前端,不管是整理成 txt/excel/markdown 文檔,亦或是寫完一個介面就直接發微信告訴前端,總是要多做一步的事情,而 Swagger 則可以幫我們省去這一步。通過配置之後,Swagger 就可以根據我們的介面自動生成 API 的介面文檔,省時,省力。當然,如果前端小姐姐單身可撩,而你碰巧有意的話,另談。

  Swagger 是一個可以將介面文檔自動生成,同時可以對介面功能進行測試的開源框架,在 ASP.NET Core 環境下,主流的有 Swashbuckle.AspNetCore 和 NSwag 這兩個開源框架幫助我們生成 Swagger documents。這裡,我採用的是 Swashbuckle.AspNetCore

  在使用 Swashbuckle.AspNetCore 之前,首先我們需要在 API(Grapefruit.WebApi) 項目中添加對於 Swashbuckle.AspNetCore 的引用。你可以直接右鍵選中 API 項目選擇管理 Nuget 程式包進行載入引用,也可以通過程式包管理控制台進行添加引用,這裡註意,使用程式包管理控制台時,你需要將預設的項目修改成 API(Grapefruit.WebApi) 項目。當引用添加完成後,我們就可以在項目中配置 Swagger 了。

Install-Package Swashbuckle.AspNetCore

  ASP.NET Core 的本質上可以看成是一個控制台程式,在我們創建好的 ASP.NET Core Web API 項目中,存在著兩個類文件:Program.cs 以及 Startup.cs。與控制台應用一樣,Program 類中的 Main 方法是整個程式的入口,在這個方法中,我們將配置好的 IWebHostBuilder 對象,構建成 IWebHost 對象,並運行該 IWebHost 對象從而達到運行 Web 項目的作用。

  在框架生成的 Program 類文件中,在配置 IWebHostBuilder 的過程時,框架預設為我們添加了一些服務,當然,這裡你可以註釋掉預設的寫法,去自己創建一個 WebHostBuilder 對象。同時,對於一個 ASP.NET Core 程式來說,Startup 類是必須的(你可以刪除生成的 Startup 類,重新創建一個新的類,但是,這個新創建的類必須包含 Configure 方法,之後只需要在 UseStartup<Startup> 中將該類配置為 Startup 類即可),這裡如果不指定 Startup 類會導致啟動失敗。

  在 Startup 類中,存在著 ConfigureServices 和 Configure 這兩個方法,在 ConfigureServices 方法中,我們將自定義服務通過依賴註入的方式添加到 IServiceCollection 容器中,而這些容器中的服務,最終都可以在 Configure 方法中進行使用;而 Configure 方法則用於指定 ASP.NET Core 應用程式將如何響應每一個 HTTP 請求,我們可以在這裡將我們自己創建的中間件(Middleware)綁定到 IApplicationBuilder 上,從而添加到 HTTP 請求管道中。

  這裡只是很粗略的說明瞭 ASP.NET Core 項目的啟動過程,想要仔細瞭解啟動過程的推薦園子里的這篇文章 =》ASP.NET Core 2.0 : 七.一張圖看透啟動背後的秘密,因為 ASP.NET Core 2.1 版本相比於 2.0 版本又有些改變,這裡有一些不一樣的地方需要你去註意。

  當我們簡單瞭解了啟動過程後,就可以配置我們的 Swagger 了。Swashbuckle.AspNetCore 幫我們構建好了使用 Swagger 的中間件,我們只需要直接使用即可。

  首先我們需要在 ConfigureServices 方法中,將我們的服務添加到 IServiceCollection 容器中,這裡,我們需要為生成的 Swagger Document 進行一些配置。

services.AddSwaggerGen(s =>
{
    s.SwaggerDoc("v1", new Info
    {
        Contact = new Contact
        {
            Name = "Danvic Wang",
            Email = "[email protected]",
            Url = "https://yuiter.com"
        },
        Description = "A front-background project build by ASP.NET Core 2.1 and Vue",
        Title = "Grapefruit.VuCore",
        Version = "v1"
    });
});

  之後,我們就可以在 Configure 方法中啟用我們的 Swagger 中間件。

app.UseSwagger();
app.UseSwaggerUI(s =>
{
    s.SwaggerEndpoint("/swagger/v1/swagger.json", "Grapefruit.VuCore API V1.0");
});

  此時,當你運行程式,在功能變數名稱後面輸入/swagger 即可訪問到我們的 API 文檔頁面。因為項目啟動時預設訪問的是我們 api/values 的 GET 請求介面,這裡我們可以打開 Properties 下的 launchSetting.json 文件去配置我們的程式預設打開頁面。

  從上面的圖可以看出,不管是使用 IIS 或是程式自托管,我們預設打開的 Url 都是 api/values,這裡我們將兩種啟動方式的 launchUrl 值都修改成 swagger 之後再次運行我們的項目,可以發現,程式預設的打開頁面就會變成我們的 API 文檔頁面。

  我們使用 API 文檔的目的,就是為了讓前端知道請求的方法地址是什麼,需要傳遞什麼參數,而現在,並沒有辦法顯示出我們對於參數以及方法的註釋,通過查看 Swashbuckle.AspNetCore 的 github 首頁可以看到,我們可以通過配置,將生成的 json 文件中包含我們對於 Controller or Action 的 Xml 註釋內容,從而達到顯示註釋信息的功能(最終呈現的 Swagger Doc 是根據之前我們定義的這個 “/swagger/v1/swagger.json” json 文件來生成的)。

  右鍵我們的 API 項目,屬性 =》生產,勾選上 XML 文檔文件,系統會預設幫我們創建生成 XML 文件的地址,這時候,我們重新生成項目,則會發現,當前項目下會多出這個 XML 文件。在重新生成項目的過程中,你會發現,錯誤列表會顯示很多警告信息,提示我們一些方法沒有添加 XML 註釋。如果你和我一樣強迫症的話,可以把 1591 這個錯誤添加到上面的禁止顯示警告中,這樣就可以不再顯示這個警告了。

  創建好 XML 的註釋文件後,我們就可以配置我們的 Swagger 文檔,從而達到顯示註釋的功能。這裡,因為我會在 Grapefruit.Application 類庫中創建各種的 Dto 對象,而介面中是會調用到這些 Dto 對象的。因此,為了顯示這些 Dto 上的註釋信息,這裡我們也需要生成 Grapefruit.Application 項目的 XML 註釋文件。

  PS:這裡我是將每個項目生成的註釋信息 xml 文檔地址都放在了程式的基礎路徑下,如果你將 xml 文檔生成在別的位置,這裡獲取 xml 的方法就需要你進行修改。

services.AddSwaggerGen(s =>
{
    //...

    //Add comments description
    //
    var basePath = Path.GetDirectoryName(AppContext.BaseDirectory);//get application located directory
    var apiPath = Path.Combine(basePath, "Grapefruit.WebApi.xml");
    var dtoPath = Path.Combine(basePath, "Grapefruit.Application.xml");
    s.IncludeXmlComments(apiPath, true);
    s.IncludeXmlComments(dtoPath, true);
});

  當我們把 Swagger 配置完成之後,我們就可以創建具有版本控制的 API 介面了。

  2、帶有版本控制的 API 介面實現

  在請求的 API Url 中標明版本號,我不知道你第一時間看到這個實現方式,會想到什麼,對於我來說,直接在路由信息中添加版本號不就可以了。。。em,這樣過於投機取巧了。。。。

[Route("api/v1/[controller]")]//添加版本信息為v1
[ApiController]
public class ValuesController : ControllerBase
{
}

  想了想,在 Url 中添加版本號,這個版本號是不是很像我們在 MVC 中使用的 Area。

  Area 是 MVC 中經常使用到的一個功能,我們通常會將某些小的模塊拆分成一個個的 Area,而這一個個的小 Area 其實就是這個 MVC 項目中的 MVC。通過為 controller 和 action 添加另一個路由參數 area,從而達到創建具有層次路由的結構。比如,這裡,我們可以創建一個 Area 叫 v1,用來存儲我們 1.x 版本的 API 介面,之後如果有新的 API 版本,新增一個 Area 即可,是不是很簡單,嗯,說乾就乾。

  右擊我們的 API 項目,選擇添加區域,新增的 Area 名稱為 v1。

  當 ASP.NET Core 的腳手架程式添加完成 Area 後,則會打開一個文件提示我們需要在 MVC 中間件中創建適用於 Area 的路由定義。

app.UseMvc(routes =>
{
  routes.MapRoute(
    name : "areas",
    template : "{area:exists}/{controller=Home}/{action=Index}/{id?}"
  );
});

  當我們添加好路由規則定義後,我們在 Area 的 Controllers 文件夾下添加一個 WebAPI Controller。不同於 ASP.NET 中的 Area ,當我們在 ASP.NET Core 創建好一個 Area 之後,腳手架生成的文件中不再有 XXXAreaRegistration(XXX 為 Area 的名稱)文件去註冊這個 Area,而我們只需要在 Area 中的 Controller 中添加 Area 特性,即可告訴系統框架,這個 Controller 是在當前的 Area 下的。

  如果你有自己嘗試的話,就會發現,當我們創建好一個 v1 的 Area 後,這個請求的地址並沒有按照我們的想法會體現在路由信息中,我們最後還是需要在 Route 中手動指明 API 版本。

[Area("v1")]
[Route("api/v1/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
}

  

  這樣的話,和最開始直接在路由信息中寫死版本信息其實也就沒什麼差別了,上網搜了搜,發現巨硬爸爸,也早已為我們準備好了實現版本控制 API 的利器 - Microsoft.AspNetCore.Mvc.Versioning。

  和上面使用 Swashbuckle.AspNetCore 的方式相同,在我們使用 Versioning 之前,需要在我們的 API 項目中添加對於該 dll 的引用。這裡需要註意下安裝的版本問題,因為 Grapefruit.VuCore 這個框架距離現在搭建也有幾個月的時間了,在這個月初的時候 .NET Core 2.2 也已經發佈了,如果你和我一樣還是採用的 .NET Core 2.1 版本的話,這裡安裝的 Versioning 版本最高只能到 2.3。

Install-Package Microsoft.AspNetCore.Mvc.Versioning

  當我們安裝完成之後,就可以進行配置了。

public void ConfigureServices(IServiceCollection services)
{
    services.AddApiVersioning(o =>
    {
        o.ReportApiVersions = true;//return versions in a response header
        o.DefaultApiVersion = new ApiVersion(1, 0);//default version select 
        o.AssumeDefaultVersionWhenUnspecified = true;//if not specifying an api version,show the default version
    });
}

  ReportApiVersions:這個配置是可選的,當我們設置為 true 時,API 會在響應的 header 中返回版本信息。

  DefaultApiVersion:指定在請求中未指明版本時要使用的預設 API 版本。這將預設版本為1.0。

  AssumeDefaultVersionWhenUnspecified:這個配置項將用於在沒有指明 API 版本的情況下提供請求,預設情況下,會請求預設版本的 API,例如,這裡就會請求 1.0 版本的 API。

  這裡,刪除我們之前的創建的 Area 和預設的 ValuesController,在 Controllers 文件夾下新增一個 v1 文件夾,將所有 v1 版本的 Controller 都建在這個目錄下。新建一個 Controller,添加上 ApiVersion Attribute 指明當前的版本信息。因為我採用的方案是在 Url 中指明 API 版本,所以,我們還需要在 Route 中修改我們的路由屬性以對應 API 的版本。這裡的 v 只是一個預設的慣例,你也可以不添加。

[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
[ApiController]
public class VaulesController : ControllerBase
{
}

  當我們修改好我們的 Controller 之後,運行我們的項目,你會發現,API 文檔中顯示的請求地址是不對的,難道是我們的配置沒起作用嗎?通過 Swagger 自帶的 API 測試工具測試下我們的介面,原來這裡請求的 Url 中已經包含了我們定義的版本信息,當我們指定錯誤的版本信息時,工具也會告訴我們這個版本的介面不存在。

  雖然我們請求的 Url 中已經帶上了版本信息,但是 API 文檔上顯示的請求地址卻是不准確的,強迫症,不能忍。這裡,需要我們修改生成 Swagger 文檔的配置代碼,將路由中的版本信息進行替換。重新運行我們的項目,可以發現,文檔顯示的 Url 地址也已經正確了,自此,我們創建帶有版本控制的 API 也就完成了。

public void ConfigureServices(IServiceCollection services)
{
    services.AddSwaggerGen(s =>
    {
        //...

        //Show the api version in url address
        s.DocInclusionPredicate((version, apiDescription) =>
        {
            var values = apiDescription.RelativePath
                .Split('/')
                .Select(v => v.Replace("v{version}", version));

            apiDescription.RelativePath = string.Join("/", values);

            return true;
        });
    });
}

 三、總結

   本章使用了 Microsoft.AspNetCore.Mvc.Versioning 這一組件來實現我們對於 API 版本控制的功能實現,可能你會有疑問,我們直接在路由中寫明版本信息不是更簡單嗎?在我看來,使用這一組件的目的,在於我們可以以多種的方式實現 API 版本控制的目的,如果哪天你不想在 Url 中指明版本信息後,你可以很快的使用別的形式來完成 API 的版本控制。另外,直接在路由中寫上版本信息,是不是會顯得我們比較 ‘low’,哈哈哈,開玩笑,最後祝大家聖誕快樂~~~


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • @[toc] "Django官網下載" MVC框架與MTV框架 MVC,全名Model View Controller,是軟體工程中的一種軟體架構模式. 把軟體系統分為三個基本部分:==模型(Model)、視圖(View)、控制器(Controller).== 優點:耦合性低、重用行高、生命周期成本 ...
  • 前言 出於對數據分析及數據挖掘的興趣,我開始接觸Python,由於缺乏編程相關知識,所以過程滿是曲折,也缺乏足量的實踐練習。寫這一系列文章的原因首先是為了鍛煉自己,因為我相信費曼的學習方法:要在教學中才能真正掌握所學的知識;其次也是想藉此機會給未入門的朋友們一些門檻比較低的參考資料,所以本系列文章均 ...
  • laravel項目顯示:No application encryption key has been specified 解決辦法: 項目根目錄下執行 php artisan key:generate ...
  • 在製作一個批量序列化工具時遇到瞭如下問題,在此記錄一下,僅供參考。 主程式載入另一個程式集,將其中的所有類取出,然後對這些類分別調用泛型類或泛型方法。控制台程式解決方案如下: Main工程:提供Worker類進行數據操作,XMLTool<T>泛型類將數據集序列化為.xml文檔,RootCollect ...
  • 軟體環境: 1、vs2015、windows7、.net4.5 演示說明: 當點擊按鈕的時候,柱狀圖數值加1並實時變化 1、首先打開vs2015創建一個mvc項目,並安裝SignalR2,具體操作可參見:http://net-yuan.com/Article/Detail/e407a472-338a ...
  • 編程語言從最初的0101機器碼到彙編語言再到面向對象的編程,不斷的發展,整個發展趨勢呈現高內聚、低耦合、可重用、可理解的特點。最早編程是用機器碼,人的大腦不像電腦,無法處理0101;後來彙編語言還是太費解,又出現了高級語言;然後因為我們需要更加接近人類語言的方式描述問題,開始出現結構化編程或者模塊化 ...
  • 開啟非同步監聽,不會導致主線程的堵塞,在服務異常斷開後一直檢測重新連接服務,成功連接服務後通知各個註冊的客戶端! #region 檢測斷線並重連OPC服務 可以強制啟動OPC服務程式 /// <summary> /// 提供外部使用 /// 重新連接事件 /// </summary> public e ...
  • 第一次整理了下關於autofac的一些具體的用法 1. 安裝 Autofac: Install-Package Autofac -Version 4.8.1 2. 創建兩個類庫項目,IService (用於編寫介面),ServiceImpl(用於創建實現類) IService 下 public in ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...