Dela via


Självstudie: Generera en REST API-klient

Ett program som använder ett REST-API är ett mycket vanligt scenario. Vanligtvis måste du generera klientkod som ditt program kan använda för att anropa REST-API:et. I den här självstudien får du lära dig hur du genererar REST API-klienten automatiskt under byggprocessen med hjälp av MSBuild. Du använder NSwag, ett verktyg som genererar klientkod för ett REST-API.

Den fullständiga exempelkoden finns på REST API-klientgenerering i .NET-exempellagringsplatsen på GitHub.

Exemplet visar en konsolapp som använder sig av det offentliga API:et för husdjurbutiken, som publicerar en OpenAPI-specifikation.

Handledningen förutsätter grundläggande kunskaper om MSBuild-termer såsom uppgifter, mål, egenskaper eller körtider. För nödvändig bakgrundsinformation, se artikeln MSBuild Koncept.

När du vill köra ett kommandoradsverktyg som en del av en version finns det två metoder att tänka på. En är att använda uppgiften MSBuild Exec, som gör att du kan köra ett kommandoradsverktyg och ange dess parametrar. Den andra metoden är att skapa en anpassad uppgift som härleds från ToolTask, vilket ger dig större kontroll.

Förutsättningar

Du bör ha en förståelse för MSBuild-begrepp som uppgifter, mål och egenskaper. Se MSBuild-begrepp.

Exemplen kräver MSBuild, som installeras med Visual Studio, men som också kan installeras separat. Se även Ladda ned MSBuild utan Visual Studio.

Alternativ 1: Exec-uppgift

Uppgiften Exec anropar bara den angivna processen med de angivna argumenten, väntar på att den ska slutföras och returnerar sedan true om processen har slutförts och false om ett fel inträffar.

NSwag-kodgenerering kan användas från MSBuild. se NSwag.MSBuild.

Den fullständiga koden finns i mappen PetReaderExecTaskExample; du kan ladda ned och ta en titt. I den här självstudien går du igenom steg för steg och lär dig begreppen på vägen.

  1. Skapa ett nytt konsolprogram med namnet PetReaderExecTaskExample. Använd .NET 6.0 eller senare.

  2. Skapa ett annat projekt i samma lösning: PetShopRestClient (Den här lösningen kommer att innehålla den genererade klienten som ett bibliotek). I det här projektet använder du .NET Standard 2.1. Den genererade klienten kompileras inte på .NET Standard 2.0.

  3. I PetReaderExecTaskExample projektet, och lägg till ett projektberoende i PetShopRestClient projektet.

  4. I PetShopRestClient-projektet inkluderar du följande NuGet-paket:

    • Nswag.MSBuild, som ger åtkomst till kodgeneratorn från MSBuild
    • Newtonsoft.Json behövs för att kompilera den genererade klienten
    • System.ComponentModel.Annotations, som behövs för att kompilera den genererade klienten
  5. I PetShopRestClient-projektet lägger du till en mapp (med namnet PetShopRestClient) för kodgenereringen och tar bort Class1.cs som genererades automatiskt.

  6. Skapa en textfil med namnet petshop-openapi-spec.json i projektets rot. Kopiera OpenAPI-specifikationen från här och spara den i filen. Det är bäst att kopiera en ögonblicksbild av specifikationen i stället för att läsa den online under bygget. Du vill alltid ha ett konsekvent reproducerbart bygge som endast beror på indata. Användning av API:et direkt kan transformera en version som fungerar idag till en version som misslyckas i morgon från samma källa. Ögonblicksbilden som sparats på petshop-openapi-spec.json gör att vi fortfarande kan ha en version som bygger även om specifikationen ändras.

  7. Ändra sedan PetShopRestClient.csproj och lägg till en MSBuild-target för att generera klienten i byggprocessen.

    Lägg först till några egenskaper som är användbara för klientgenerering:

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

    Lägg till följande mål:

     <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>
    

    Observera att det här målet använder attributen BeforeTarget och AfterTarget som sätt att definiera byggordning. Det första målet med namnet generatePetClient körs före huvudkompileringsmålet, så källan skapas innan kompilatorn körs. Parametrarna indata och utdata är relaterade till inkrementell kompilering. MSBuild kan jämföra tidsstämplarna för indatafilerna med tidsstämplarna för utdatafilerna och avgöra om du vill hoppa över, skapa eller delvis återskapa ett mål.

    När du har installerat NSwag.MSBuild NuGet-paketet i projektet kan du använda variabeln $(NSwagExe) i filen .csproj för att köra kommandoradsverktyget NSwag i ett MSBuild-mål. På så sätt kan verktygen enkelt uppdateras via NuGet. Här använder du uppgiften Exec MSBuild för att köra NSwag-programmet med de parametrar som krävs för att generera klientens rest-API. Se NSwag-kommando och parametrar.

    Du kan samla in utdata från <Exec> lägga till ConsoleToMsBuild="true" i taggen <Exec> och sedan samla in utdata med parametern ConsoleOutput i en <Output> tagg. ConsoleOutput returnerar utdata som en Item. Mellanrum tas bort. ConsoleOutput aktiveras när ConsoleToMSBuild är sant.

    Det andra målet som kallas forceReGenerationOnRebuild raderar den genererade klassen vid rensning för att tvinga fram nygenerering av den genererade koden vid återskapande av målet. Det här målet körs efter MSBuilds fördefinierade mål CoreClean.

  8. Kör en återskapning av Visual Studio-lösningen och se klienten som genereras i mappen PetShopRestClient.

  9. Använd nu den genererade klienten. Gå till klienten Program.csoch kopiera följande kod:

    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}");
           }
       }
    }
    

    Not

    Den här koden använder new HttpClient() eftersom den är enkel att demonstrera, men det är inte den bästa metoden för verklig kod. Det bästa sättet är att använda HttpClientFactory för att skapa ett HttpClient objekt som åtgärdar kända problem med HttpClient begäran, till exempel resursöverbelastning eller inaktuella DNS-problem. Se Använda IHttpClientFactory för att implementera elastiska HTTP-begäranden.

Grattis! Nu kan du köra programmet för att se hur det fungerar.

Alternativ 2: Anpassad uppgift härledd från ToolTask

I många fall är det tillräckligt bra att använda Exec uppgift för att köra ett externt verktyg för att göra något som liknar REST API-klientkodgenerering, men vad händer om du vill tillåta REST API-klientkodgenerering om och bara om du inte använder en absolut Windows-sökväg som indata? Eller vad händer om du behöver beräkna på något sätt var den körbara filen finns? När det finns situationer där du behöver köra kod för att utföra extra arbete är MSBuild Tool Task den bästa lösningen. Klassen ToolTask är en abstrakt klass som härleds från MSBuild Task. Du kan definiera en konkret underklass som skapar en anpassad MSBuild-uppgift. Med den här metoden kan du köra all kod som behövs för att förbereda för kommandokörning. Du bör läsa handledningen Skapa en anpassad uppgift för kodgenerering först.

Du skapar en anpassad uppgift som härleds från MSBuild ToolTask som genererar en REST API-klient, men den kommer att utformas för att generera ett fel om du försöker referera till OpenAPI-specifikationen med hjälp av en HTTP-adress. NSwag stöder en http-adress som OpenAPI-specifikationsindata, men i det här exemplet antar vi att det finns ett designkrav för att inte tillåta det.

Den fullständiga koden finns i den här PetReaderToolTaskExample mappen. du kan ladda ned och ta en titt. I den här självstudien går du igenom steg för steg och lär dig några begrepp som du kan använda för dina egna scenarier.

  1. Skapa ett nytt Visual Studio-projekt för den anpassade aktiviteten. Anropa det RestApiClientGenerator och använd mallen Class Library (C#) med .NET Standard 2.0. Ge lösningen namnet PetReaderToolTaskExample.

  2. Ta bort Class1.cs, som genererades automatiskt.

  3. Lägg till Microsoft.Build.Utilities.Core NuGet-paket:

    • Skapa en klass med namnet RestApiClientGenerator

    • Ärva från MSBuild ToolTask och implementera den abstrakta metoden enligt följande kod:

      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. Lägg till följande parametrar:

    • InputOpenApiSpec, där specifikationen är
    • ClientClassName, namnet på den genererade klassen
    • ClientNamespaceName, namnområde där klassen genereras
    • FolderClientClass, sökväg till mappen där klassen ska finnas
    • NSwagCommandFullPath, fullständig sökväg till katalogen där NSwag.exe finns
         [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. Installera kommandoradsverktyget NSwag. Du behöver den fullständiga sökvägen till katalogen där NSwag.exe finns.

  6. Implementera abstrakta metoder:

       protected override string ToolName => "RestApiClientGenerator";
    
       protected override string GenerateFullPathToTool()
       {
           return $"{NSwagCommandFullPath}\\NSwag.exe";
       }
    
  7. Det finns många metoder som du kan åsidosätta. För den aktuella implementeringen definierar du följande två:

    • Definiera kommandoparametern:
      protected override string GenerateCommandLineCommands()
      {
          return $"openapi2csclient /input:{InputOpenApiSpec}  /classname:{ClientClassName} /namespace:{ClientNamespaceName} /output:{FolderClientClass}\\{ClientClassName}.cs";
      }
    
    • Parameterverifiering:
    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;
    }
    

    Not

    Den här enkla valideringen kan göras på annat sätt i MSBuild-filen, men vi rekommenderar att du gör det i C#-kod och kapslar in kommandot och logiken.

  8. Skapa projektet.

Skapa en konsolapp för att använda den nya MSBuild-uppgiften

Nästa steg är att skapa en app som använder uppgiften.

  1. Skapa ett konsolapp-projekt och ge det namnet PetReaderToolTaskConsoleApp. Välj .NET 6.0. Markera det som startprojekt.

  2. Skapa ett klassbibliotek projekt för att generera koden, med namnet PetRestApiClient. Använd .NET Standard 2.1.

  3. I PetReaderToolTaskConsoleApp-projektet skapar du ett projektberoende till PetRestApiClient.

  4. I PetRestApiClient-projektet skapar du en mapp PetRestApiClient. Den här mappen innehåller den genererade koden.

  5. Ta bort Class1.cs, som genererades automatiskt.

  6. PetRestApiClientlägger du till följande NuGet-paket:

    • Newtonsoft.Json behövs för att kompilera den genererade klienten
    • System.ComponentModel.Annotations, som behövs för att kompilera den genererade klienten
  7. I PetRestApiClient-projektet skapar du en textfil med namnet petshop-openapi-spec.json (i projektmappen). Om du vill lägga till OpenAPI-specifikationen kopierar du innehållet från här till filen. Vi gillar en reproducerbar version som bara beror på indata, som vi beskrev tidigare. I det här exemplet skapar du ett byggfel om en användare väljer en URL som OpenAPI-specifikationsindata.

    Viktig

    En allmän ombyggnad fungerar inte. Du ser fel som indikerar att det inte går att kopiera eller ta bort RestApiClientGenerator.dll. Det beror på att den försöker skapa den anpassade MBuild-uppgiften i samma byggprocess som använder den. Välj PetReaderToolTaskConsoleApp och återskapa endast projektet. En annan lösning är att placera den anpassade uppgiften i en helt oberoende Visual Studio-lösning som du gjorde i Självstudie: Skapa en anpassad uppgift exempel.

  8. Kopiera följande kod till 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. Ändra MSBuild-instruktionerna för att anropa uppgiften och generera koden. Redigera PetRestApiClient.csproj genom att följa dessa steg:

    1. Registrera användningen av den anpassade MSBuild-uppgiften:

      <UsingTask TaskName="RestApiClientGenerator.RestApiClientGenerator" AssemblyFile="..\RestApiClientGenerator\bin\Debug\netstandard2.0\RestApiClientGenerator.dll" />
      
    2. Lägg till några egenskaper som krävs för att köra uppgiften:

       <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>
      

      Viktig

      Välj rätt NSwagCommandFullPath värde baserat på installationsplats i systemet.

    3. Lägg till ett MSBuild-mål för att generera klientprogrammet under byggprocessen. Det här målet ska köras innan CoreCompile körs för att generera koden som används i kompilering.

      <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>
      

    Input och Output är relaterade till inkrementell kompilering, och målet forceReGenerationOnRebuild tar bort den genererade filen efter CoreClean, vilket tvingar klienten att återskapas under omkompileringen.

  10. Välj PetReaderToolTaskConsoleApp och återskapa endast projektet. Nu genereras klientkoden och koden kompileras. Du kan köra den och se hur den fungerar. Den här koden genererar koden från en fil och det är tillåtet.

  11. I det här steget demonstrerar du parameterverifieringen. I PetRestApiClient.csprojändrar du egenskapen $(PetClientInputOpenApiSpec) för att använda URL:en:

      <PetClientInputOpenApiSpec>https://petstore.swagger.io/v2/swagger.json</PetClientInputOpenApiSpec>
    
  12. Välj PetReaderToolTaskConsoleApp och återskapa endast projektet. Du får felet "URL tillåts inte" i enlighet med designkravet.

Ladda ned koden

Installera kommandoradsverktyget NSwag. Sedan behöver du den fullständiga sökvägen till katalogen där NSwag.exe finns. Därefter redigerar du PetRestApiClient.csproj och väljer rätt $(NSwagCommandFullPath) värde baserat på installationssökvägen på din dator. Välj nu RestApiClientGenerator och bygg endast det projektet, och välj slutligen PetReaderToolTaskConsoleAppoch återskapa det. Du kan köra PetReaderToolTaskConsoleApp. för att kontrollera att allt fungerar som förväntat.

Nästa steg

Du kanske vill publicera din anpassade uppgift som ett NuGet-paket.

Eller lär dig hur du testar en anpassad uppgift.