共用方式為


教學課程:產生 REST API 用戶端

取用 REST API 的應用程式是非常常見的案例。 通常,您必須產生用戶端程式代碼,您的應用程式可用來呼叫 REST API。 在本教學課程中,您將瞭解如何使用 MSBuild 在建置程式期間自動產生 REST API 用戶端。 您將使用 NSwag,此工具會產生 REST API 的用戶端程式代碼。

完整的範例程式代碼可在 GitHub 上的 .NET 範例存放庫中 REST API 用戶端產生 取得。

此範例顯示會使用公用 寵物市集 API的主控台應用程式,其會發布 OpenAPI 規格

本教學課程假設 MSBuild 詞彙的基本知識,例如工作、目標、屬性或運行時間;如需必要的背景,請參閱 msBuild 概念 文章

當您想要在組建中執行命令行工具時,有兩種方法需要考慮。 其中一個是使用 MSBuild Exec 工作,這可讓您執行命令行工具並指定其參數。 另一種方法是建立衍生自 ToolTask的自定義工作,這可提供您更大的控制權。

先決條件

您應該瞭解 MSBuild 概念,例如工作、目標和屬性。 請參閱 msBuild 概念

這些範例需要隨 Visual Studio 一起安裝的 MSBuild,但也可以個別安裝。 請參閱 參考章節:下載不含 Visual Studio 的 MSBuild

選項 1:執行工作

Exec 工作 只要使用指定的自變數叫用指定的進程、等候它完成,然後傳回 true 如果進程順利完成,如果發生錯誤,false

NSwag 程式代碼產生可從 MSBuild 使用;請參閱 NSwag.MSBuild

完整的程式代碼位於 PetReaderExecTaskExample 資料夾中;您可以下載並查看。 在本教學課程中,您將逐步完成並了解相關概念。

  1. 建立名為 PetReaderExecTaskExample的新控制台應用程式。 使用 .NET 6.0 或更新版本。

  2. 在相同的方案中建立另一個專案:PetShopRestClient (此解決方案將包含產生的用戶端作為連結庫)。 針對此專案,請使用 .NET Standard 2.1。 產生的用戶端不會在 .NET Standard 2.0 上編譯。

  3. PetReaderExecTaskExample 專案中,將專案相依性新增至 PetShopRestClient 專案。

  4. PetShopRestClient 專案中,包含下列 NuGet 套件:

    • Nswag.MSBuild,允許從 MSBuild 存取程式代碼產生器
    • 編譯產生的客戶端所需的 Newtonsoft.Json
    • System.ComponentModel.Annotations 是編譯產生的用戶端所需的
  5. PetShopRestClient 專案中,新增程式代碼產生的資料夾(名為 PetShopRestClient),並刪除自動產生的 Class1.cs

  6. 在專案的根目錄建立名為 petshop-openapi-spec.json 的文字檔。 從此處 複製 OpenAPI 規格 並將它儲存在檔案中。 最好在建構過程中複製規格的快照,而不是在線上閱讀。 您一律想要一致的可重現組建,而該組建只取決於輸入。 直接使用 API 可能會導致今天運作正常的組建在明天因相同來源而失敗。 儲存在 petshop-openapi-spec.json 上的快照可讓我們,即使規格變更,仍然有一個版本可以組建。

  7. 接下來,修改 PetShopRestClient.csproj,並新增 MSBuild 目標,以在建置程式期間產生用戶端。

    首先,新增一些適用於客戶端產生的屬性:

     <PropertyGroup>
         <PetOpenApiSpecLocation>petshop-openapi-spec.json</PetOpenApiSpecLocation>
         <PetClientClassName>PetShopRestClient</PetClientClassName>
         <PetClientNamespace>PetShopRestClient</PetClientNamespace>
         <PetClientOutputDirectory>PetShopRestClient</PetClientOutputDirectory>
     </PropertyGroup>
    

    新增下列目標:

     <Target Name="generatePetClient" BeforeTargets="CoreCompile" Inputs="$(PetOpenApiSpecLocation)" Outputs="$(PetClientOutputDirectory)\$(PetClientClassName).cs">
         <Exec Command="$(NSwagExe) openapi2csclient /input:$(PetOpenApiSpecLocation)  /classname:$(PetClientClassName) /namespace:$(PetClientNamespace) /output:$(PetClientOutputDirectory)\$(PetClientClassName).cs" ConsoleToMSBuild="true">
         <Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" />
       </Exec>
     </Target>
     <Target Name="forceReGenerationOnRebuild" AfterTargets="CoreClean">
        <Delete Files="$(PetClientOutputDirectory)\$(PetClientClassName).cs"></Delete>
     </Target>
    

    請注意,此目標使用 BeforeTarget 和 AfterTarget 屬性來定義編譯順序。 第一個稱為 generatePetClient 的目標會在核心編譯目標之前執行,因此在編譯程序執行之前,會先建立來源。 輸入和輸出參數與 累加建置相關。 MSBuild 可以將輸入檔的時間戳與輸出檔案的時間戳進行比較,並判斷是否要略過、建置或部分重建目標。

    在專案中安裝 NSwag.MSBuild NuGet 套件之後,您可以使用 $(NSwagExe) 檔案中的變數 .csproj,在 MSBuild 目標中執行 NSwag 命令行工具。 如此一來,工具即可透過 NuGet 輕鬆更新。 在這裡,您會使用 Exec MSBuild 工作來執行 NSwag 程式,並搭配必要的參數,以生成用戶端的 REST API。 請參閱 NSwag 命令和參數

    您可以從 <Exec> 擷取輸出,將 ConsoleToMsBuild="true" 新增至 <Exec> 標記,然後使用 ConsoleOutput 標記中的 <Output> 參數擷取輸出。 ConsoleOutput 會以 Item傳回輸出。 會修剪空白。 當 ConsoleOutput 為 true 時,會啟用 ConsoleToMSBuild

    第二個稱為 forceReGenerationOnRebuild 的目標會在清除期間刪除產生的類別,以強制在重建目標執行期間重新產生產生的程序代碼。 此目標會在 MSBuild 預先定義的目標 CoreClean 之後執行。

  8. 執行 Visual Studio 方案重建,並查看在 PetShopRestClient 資料夾上產生的用戶端。

  9. 現在,使用產生的用戶端。 移至用戶端 Program.cs,然後複製下列程式代碼:

    using System;
    using System.Net.Http;
    
    namespace PetReaderExecTaskExample
    {
       internal class Program
       {
           private const string baseUrl = "https://petstore.swagger.io/v2";
           static void Main(string[] args)
           {
               HttpClient httpClient = new HttpClient();
               httpClient.BaseAddress = new Uri(baseUrl);
               var petClient = new PetShopRestClient.PetShopRestClient(httpClient);
               var pet = petClient.GetPetByIdAsync(1).Result;
               Console.WriteLine($"Id: {pet.Id} Name: {pet.Name} Status: {pet.Status} CategoryName: {pet.Category.Name}");
           }
       }
    }
    

    注意

    此程式代碼會使用 new HttpClient(),因為它很容易示範,但它不是真實世界程序代碼的最佳做法。 最佳做法是使用 HttpClientFactory 來建立 HttpClient 物件,以解決資源耗盡或過時 DNS 問題等 HttpClient 要求的已知問題。 請參閱 使用 IHttpClientFactory 來執行具復原能力的 HTTP 請求

祝賀! 現在,您可以執行程式來查看其運作方式。

選項 2:衍生自 ToolTask 的自定義工作

在許多情況下,使用 Exec 工作就足以執行外部工具來進行 REST API 用戶端程式碼的產生,但如果您只在不使用絕對 Windows 路徑做為輸入時,還想允許進行 REST API 用戶端程式碼的產生呢? 或者,如果您需要以某種方式計算可執行檔的所在位置,該怎麼辦? 當您需要執行某些程式代碼來執行額外工作時,MSBuild 工具工作 是最佳解決方案。 ToolTask 類別是衍生自 MSBuild Task的抽象類。 您可以定義可建立自訂 MSBuild 工作的具象子類別。 此方法可讓您執行準備命令執行所需的任何程序代碼。 您應該先閱讀教學指南,建立程式碼生成 的自定義工作。

您將建立衍生自 MSBuild ToolTask 的自定義工作,這會產生 REST API 用戶端,但如果您嘗試使用 HTTP 位址參考 OpenAPI 規格,則會設計為發出錯誤。 NSwag 支援 HTTP 位址做為 OpenAPI 規格輸入,但為了這個範例的目的,假設有一個設計需求不允許這樣做。

完整的程式代碼位於此 PetReaderToolTaskExample 資料夾中;您可以下載並查看。 在本教學課程中,您將逐步瞭解一些概念,這些概念可套用至您自己的案例。

  1. 為自定義工作建立新的Visual Studio專案。 稱它為 RestApiClientGenerator,並使用 類別程式庫(C#) 範本並搭配 .NET Standard 2.0。 將專案命名為 PetReaderToolTaskExample

  2. 刪除自動產生的 Class1.cs

  3. 新增 Microsoft.Build.Utilities.Core NuGet 套件包:

    • 建立名為 RestApiClientGenerator 的類別

    • 繼承自 MSBuild ToolTask 並實作抽象方法,如下列程式代碼所示:

      using Microsoft.Build.Utilities;
      
      namespace RestApiClientGenerator
      {
          public class RestApiClientGenerator : ToolTask
          {
              protected override string ToolName => throw new System.NotImplementedException();
      
              protected override string GenerateFullPathToTool()
              {
                  throw new System.NotImplementedException();
              }
          }
      }
      
  4. 新增下列參數:

    • InputOpenApiSpec,其中規格為
    • ClientClassName,產生的類別名稱
    • ClientNamespaceName,產生類別的命名空間
    • FolderClientClass,類別所在資料夾的路徑
    • NSwagCommandFullPath,NSwag.exe 所在目錄的完整路徑
         [Required]
         public string InputOpenApiSpec { get; set; }
         [Required]
         public string ClientClassName { get; set; }
         [Required]
         public string ClientNamespaceName { get; set; }
         [Required]
         public string FolderClientClass { get; set; }
         [Required]
         public string NSwagCommandFullPath { get; set; }
    
  5. 安裝 NSwag 命令列工具。 您需要 NSwag.exe 所在目錄的完整路徑。

  6. 實作抽象方法:

       protected override string ToolName => "RestApiClientGenerator";
    
       protected override string GenerateFullPathToTool()
       {
           return $"{NSwagCommandFullPath}\\NSwag.exe";
       }
    
  7. 有許多方法可以覆寫。 針對目前的實作,請定義這兩個:

    • 定義命令參數:
      protected override string GenerateCommandLineCommands()
      {
          return $"openapi2csclient /input:{InputOpenApiSpec}  /classname:{ClientClassName} /namespace:{ClientNamespaceName} /output:{FolderClientClass}\\{ClientClassName}.cs";
      }
    
    • 參數驗證:
    protected override bool ValidateParameters()
    {
          //http address is not allowed
          var valid = true;
          if (InputOpenApiSpec.StartsWith("http:") || InputOpenApiSpec.StartsWith("https:"))
          {
              valid = false;
              Log.LogError("URL is not allowed");
          }
    
          return valid;
    }
    

    注意

    這個簡單的驗證可以在 MSBuild 檔案上以其他方式完成,但建議在 C# 程式代碼中執行此驗證,並封裝命令和邏輯。

  8. 建置專案。

建立主控台應用程式以使用新的 MSBuild 工作

下一個步驟是建立使用工作的應用程式。

  1. 建立 主控台應用程式 專案,並將其命名為 PetReaderToolTaskConsoleApp。 選擇 [.NET 6.0]。 將它標示為啟始專案。

  2. 建立 類別庫 專案,以產生稱為 PetRestApiClient的程序代碼。 使用 .NET Standard 2.1。

  3. PetReaderToolTaskConsoleApp 專案中,建立對 PetRestApiClient的專案相依性。

  4. PetRestApiClient 專案中,建立資料夾 PetRestApiClient。 此資料夾將包含產生的程式代碼。

  5. 刪除自動產生的 Class1.cs

  6. PetRestApiClient上,新增下列 NuGet 套件:

    • 編譯產生的客戶端所需的 Newtonsoft.Json
    • System.ComponentModel.Annotations 是編譯產生的用戶端所需的
  7. PetRestApiClient 專案中,建立名為 petshop-openapi-spec.json 的文字檔(在專案資料夾中)。 若要新增 OpenAPI 規格,請將此處 的內容複製到檔案。 我們喜歡只依賴輸入的可重現組建,如先前所述。 在此範例中,如果使用者選擇 URL 做為 OpenAPI 規格輸入,您將引發建置錯誤。

    重要

    通用的重建行不通。 您會看到顯示無法複製或刪除 RestApiClientGenerator.dll的錯誤訊息。 這是因為它正嘗試在使用它的相同建置程式中建置 MBuild 自定義工作。 選取 [PetReaderToolTaskConsoleApp],然後只重建該專案。 另一個解決方案是將自定義工作放在完全獨立的Visual Studio解決方案中,如同您在 教學課程:建立自定義工作 範例中所做的一樣。

  8. 將下列程式代碼複製到 Program.cs

     using System;
     using System.Net.Http;
     namespace PetReaderToolTaskConsoleApp
     {
       internal class Program
       {
           private const string baseUrl = "https://petstore.swagger.io/v2";
           static void Main(string[] args)
           {
               HttpClient httpClient = new HttpClient();
               httpClient.BaseAddress = new Uri(baseUrl);
               var petClient = new PetRestApiClient.PetRestApiClient(httpClient);
               var pet = petClient.GetPetByIdAsync(1).Result;
               Console.WriteLine($"Id: {pet.Id} Name: {pet.Name} Status: {pet.Status} CategoryName: {pet.Category.Name}");
           }
       }
     }
    
  9. 變更 MSBuild 指示以呼叫工作並產生程式代碼。 依照下列步驟編輯 PetRestApiClient.csproj

    1. 註冊 MSBuild 自訂任務的用法:

      <UsingTask TaskName="RestApiClientGenerator.RestApiClientGenerator" AssemblyFile="..\RestApiClientGenerator\bin\Debug\netstandard2.0\RestApiClientGenerator.dll" />
      
    2. 新增執行工作所需的一些屬性:

       <PropertyGroup>
          <!--The place where the OpenAPI spec is in-->
         <PetClientInputOpenApiSpec>petshop-openapi-spec.json</PetClientInputOpenApiSpec>
         <PetClientClientClassName>PetRestApiClient</PetClientClientClassName>
         <PetClientClientNamespaceName>PetRestApiClient</PetClientClientNamespaceName>
         <PetClientFolderClientClass>PetRestApiClient</PetClientFolderClientClass>
         <!--The directory where NSawg.exe is in-->
         <NSwagCommandFullPath>C:\Nsawg\Win</NSwagCommandFullPath>
        </PropertyGroup>
      

      重要

      根據系統上的安裝位置,選取適當的 NSwagCommandFullPath 值。

    3. 新增 MSBuild 目標,以在建置程式期間產生用戶端。 此目標應該會在執行 CoreCompile 之前執行,以產生編譯中使用的程式代碼。

      <Target Name="generatePetClient" BeforeTargets="CoreCompile" Inputs="$(PetClientInputOpenApiSpec)" Outputs="$(PetClientFolderClientClass)\$(PetClientClientClassName).cs">
        <!--Calling our custom task derivated from MSBuild Tool Task-->
        <RestApiClientGenerator InputOpenApiSpec="$(PetClientInputOpenApiSpec)" ClientClassName="$(PetClientClientClassName)" ClientNamespaceName="$(PetClientClientNamespaceName)" FolderClientClass="$(PetClientFolderClientClass)" NSwagCommandFullPath="$(NSwagCommandFullPath)"></RestApiClientGenerator>
      </Target>
      
      <Target Name="forceReGenerationOnRebuild" AfterTargets="CoreClean">
        <Delete Files="$(PetClientFolderClientClass)\$(PetClientClientClassName).cs"></Delete>
      </Target>
      

    InputOutput累加建置相關,而 forceReGenerationOnRebuild 目標會在 CoreClean之後刪除產生的檔案,這會強制用戶端在重建作業期間重新產生。

  10. 選取 [PetReaderToolTaskConsoleApp],然後只重建該專案。 現在,客戶端代碼已生成,並且代碼已編譯。 您可以執行它,並查看其運作方式。 此程式會從檔案產生程式代碼,這是被允許的。

  11. 在此步驟中,您將示範參數驗證。 在 PetRestApiClient.csproj中,將 屬性 $(PetClientInputOpenApiSpec) 變更為使用 URL:

      <PetClientInputOpenApiSpec>https://petstore.swagger.io/v2/swagger.json</PetClientInputOpenApiSpec>
    
  12. 選取 [PetReaderToolTaskConsoleApp],然後只重建該專案。 您將根據設計需求收到「不允許 URL」錯誤。

下載程序代碼

安裝 NSwag 命令列工具。 然後,您將需要 NSwag.exe 所在目錄的完整路徑。 之後,請編輯 PetRestApiClient.csproj,並根據計算機上的安裝路徑選取適當的 $(NSwagCommandFullPath) 值。 現在,選取 RestApiClientGenerator 並只建置該專案,最後選取並重建 PetReaderToolTaskConsoleApp。 您可以執行 PetReaderToolTaskConsoleApp。 以確認一切如預期般運作。

後續步驟

您可能想要將自定義工作發佈為 NuGet 套件。

或者,瞭解如何測試自定義工作。