Tutorial: Generieren eines REST-API-Clients

Eine Anwendung, die eine REST-API nutzt, ist ein sehr häufiges Szenario. In der Regel müssen Sie Clientcode generieren, den Ihre Anwendung zum Aufrufen der REST-API verwenden kann. In diesem Tutorial erfahren Sie, wie Sie den REST-API-Client automatisch während des Buildprozesses mithilfe von MSBuild generieren. Sie verwenden NSwag, ein Tool, das Clientcode für eine REST-API generiert.

Der vollständige Beispielcode ist unter REST API client generation (REST-API-Clientgenerierung) im .NET-Beispielerepository auf GitHub verfügbar.

Das Beispiel zeigt eine Konsolen-App, die die öffentliche Pet Store-API verwendet, die eine OpenAPI-Spezifikation veröffentlicht.

In diesem Tutorial werden grundlegende Kenntnisse von MSBuild vorausgesetzt, z. B. von Tasks, Zielen, Eigenschaften oder Laufzeiten. Den erforderlichen Hintergrund finden Sie im Artikel zu den MSBuild-Konzepten.

Wenn Sie ein Befehlszeilentool als Teil eines Builds ausführen möchten, kommen zwei Ansätze in Betracht. Ein Ansatz besteht darin, den Exec-Task von MSBuild zu verwenden, mit dem Sie ein Befehlszeilentool ausführen und Parameter angeben können. Die andere Methode besteht darin, einen benutzerdefinierten Task zu erstellen, der von ToolTask abgeleitet wurde, wodurch Sie mehr Kontrolle erhalten.

Voraussetzungen

Sie sollten mit den MSBuild-Konzepten wie Tasks, Zielen und Eigenschaften vertraut sein. Weitere Informationen finden Sie unter MSBuild-Konzepte.

Die Beispiele erfordern MSBuild. Diese Engine wird mit Visual Studio installiert, kann aber auch separat installiert werden. Weitere Informationen finden Sie unter Herunterladen von MSBuild ohne Visual Studio.

Option 1: Exec-Task

Der Exec-Task ruft einfach den angegebenen Prozess mit den angegebenen Argumenten auf, wartet, bis er abgeschlossen wurde, und gibt dann true zurück, wenn der Prozess erfolgreich abgeschlossen wurde, und false, wenn ein Fehler aufgetreten ist.

NSwag-Codegenerierung kann aus MSBuild verwendet werden. Weitere Informationen finden Sie unter NSwag.MSBuild.

Der vollständige Code befindet sich im Ordner PetReaderExecTaskExample. Sie können ihn herunterladen und einen Blick darauf werfen. In diesem Tutorial werden Sie den Code Schritt für Schritt durchgehen und sich dabei mit den Konzepten vertraut machen.

  1. Erstellen Sie eine neue Konsolenanwendung namens PetReaderExecTaskExample. Verwenden Sie .NET 6.0 oder höher.

  2. Erstellen Sie ein weiteres Projekt in derselben Projektmappe: PetShopRestClient (diese Projektmappe wird den generierten Client als Bibliothek enthalten). Verwenden Sie für dieses Projekt .NET Standard 2.1. Der generierte Client wird in .NET Standard 2.0 nicht kompiliert.

  3. Fügen Sie im PetReaderExecTaskExample-Projekt eine Projektabhängigkeit zum PetShopRestClient-Projekt hinzu.

  4. Binden Sie im PetShopRestClient-Projekt die folgenden NuGet-Pakete ein:

    • Nswag.MSBuild, das Zugriff auf den Code-Generator aus MSBuild ermöglicht.
    • Newtonsoft.Json, das erforderlich ist, um den generierten Client zu kompilieren.
    • System.ComponentModel.Annotations: erforderlich, um den generierten Client zu kompilieren.
  5. Fügen Sie im PetShopRestClient-Projekt einen Ordner (namens PetShopRestClient) für die Codegenerierung hinzu, und löschen Sie die automatisch generierte Datei Class1.cs.

  6. Erstellen Sie im Stammverzeichnis des Projekts eine Textdatei mit dem Namen petshop-openapi-spec.json. Kopieren Sie die OpenApi-Spezifikation von hier, und speichern Sie sie in der Datei. Es ist am besten, eine Momentaufnahme der Spezifikation zu kopieren, anstatt sie während des Buildvorgangs online zu lesen. Sie möchten immer einen konsistent reproduzierbaren Build, der nur von der Eingabe abhängt. Durch direktes Nutzen der API kann ein Build, der heute funktioniert, in einen Build transformiert werden, der morgen aus derselben Quelle fehlschlägt. Die in petshop-openapi-spec.json gespeicherte Momentaufnahme ermöglicht es uns, weiterhin eine Version zu haben, die kompiliert wird, auch wenn sich die Spezifikation ändert.

  7. Ändern Sie im nächsten Schritt „PetShopRestClient.csproj“, und fügen Sie ein MSBuild-Ziel hinzu, um den Client während des Buildprozesses zu generieren.

    Fügen Sie zunächst einige Eigenschaften hinzu, die für Clientgenerierung nützlich sind:

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

    Fügen Sie die folgenden Ziele hinzu:

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

    Beachten Sie, dass dieses Ziel die Attribute BeforeTarget und AfterTarget verwendet, um die Buildreihenfolge zu definieren. Das erste Ziel namens generatePetClient wird vor dem Kernkompilierungsziel ausgeführt, sodass die Quelle erstellt wird, bevor der Compiler ausgeführt wird. Die Eingabe- und Ausgabeparameter beziehen sich auf inkrementelle Builds. MSBuild kann die Zeitstempel der Eingabedatei mit den Zeitstempeln der Ausgabedateien vergleichen und bestimmen, ob ein Ziel übersprungen, erstellt oder teilweise neu erstellt wird.

    Nach der Installation des NuGet-Pakets NSwag.MSBuild in Ihrem Projekt können Sie die Variable $(NSwagExe) in Ihrer .csproj-Datei verwenden, um das NSwag-Befehlszeilentool in einem MSBuild-Ziel auszuführen. Auf diese Weise können die Tools problemlos über NuGet aktualisiert werden. Hier verwenden Sie den Exec-Task von MSBuild, um das NSwag-Programm mit den erforderlichen Parametern auszuführen, um die Client-REST-API zu generieren. Weitere Informationen finden Sie unter NSwag-Befehl und -Parameter.

    Sie können die Ausgabe aus <Exec> erfassen, indem Sie Ihrem <Exec>-Tag ConsoleToMsBuild="true" hinzufügen und dann die Ausgabe mithilfe des ConsoleOutput-Parameters in einem <Output>-Tag erfassen. ConsoleOutput gibt die Ausgabe als Item zurück. Leerzeichen werden abgeschnitten. ConsoleOutput ist aktiviert, wenn ConsoleToMSBuild TRUE ist.

    Das zweite Ziel mit dem Namen forceReGenerationOnRebuild löscht die generierte Klasse während der Bereinigung, um die Neugenerierung des generierten Codes während der Ausführung der Neuerstellung des Ziels zu erzwingen. Dieses Ziel wird nach dem vordefinierten MSBuild-CoreClean-Ziel ausgeführt.

  8. Führen Sie die Neuerstellung einer Visual Studio-Projektmappe aus, und sehen Sie, wie der Client im Ordner PetShopRestClient generiert wird.

  9. Verwenden Sie nun den generierten Client. Wechseln Sie zur Clientdatei Program.cs, und kopieren Sie den folgenden Code:

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

    Hinweis

    Dieser Code verwendet new HttpClient(), da dies einfach zu veranschaulichen ist, aber es ist nicht die beste Praxis für realen Code. Am besten verwenden Sie HttpClientFactory, um ein HttpClient-Objekt zu erstellen, das die bekannten Probleme von HttpClient-Anforderungen wie Ressourcenerschöpfung oder veraltete DNS-Probleme beseitigt. Weitere Informationen finden Sie unter Verwenden von IHttpClientFactory zur Implementierung robuster HTTP-Anforderungen.

Herzlichen Glückwunsch! Nun können Sie das Programm ausführen, um zu sehen, wie es funktioniert.

Option 2: Von ToolTask abgeleiteter benutzerdefinierter Task

In vielen Fällen ist die Verwendung des Exec-Tasks ausreichend, um ein externes Tool auszuführen, um eine Aufgabe wie Rest-API-Clientcodegenerierung auszuführen. Wie ist aber vorzugehen, wenn Sie die Rest-API-Clientcodegenerierung nur zulassen möchten, wenn Sie keinen absoluten Windows-Pfad als Eingabe verwenden? Oder wenn Sie irgendwie berechnen müssen, wo sich die ausführbare Datei befindet? In Situationen, in denen Sie Code ausführen müssen, um zusätzliche Aufgaben zu erledigen, ist der Tool-Task von MSBuild die beste Lösung. Die ToolTask-Klasse ist eine abstrakte Klasse, die von MSBuild Task abgeleitet ist. Sie können eine konkrete Unterklasse definieren, die einen benutzerdefinierten MSBuild-Task erstellt. Mit diesem Ansatz können Sie beliebigen Code ausführen, der für die Vorbereitung der Befehlsausführung erforderlich ist. Lesen Sie zunächst das Tutorial Erstellen eines benutzerdefinierten Tasks für Codegenerierung.

Sie erstellen einen benutzerdefinierten Task, der von ToolTask von MSBuild abgeleitet ist und einen REST-API-Client generiert. Dieser ist jedoch so konzipiert, dass er einen Fehler ausgibt, wenn Sie versuchen, über eine HTTP-Adresse auf die OpenApi-Spezifikation zu verweisen. NSwag unterstützt eine HTTP-Adresse als Eingabe der OpenApi-Spezifikation. Im Rahmen dieses Beispiels wird jedoch angenommen, dass es eine Entwurfsanforderung gibt, die dies nicht gestattet.

Der vollständige Code befindet sich in diesem Ordner PetReaderToolTaskExample. Sie können ihn herunterladen und einen Blick darauf werfen. In diesem Tutorial werden Sie ihn Schritt für Schritt durchlaufen und einige Konzepte kennenlernen, die Sie auf Ihre eigenen Szenarien anwenden können.

  1. Erstellen Sie ein neues Visual Studio-Projekt für den benutzerdefinierten Task. Nennen Sie es RestApiClientGenerator, und verwenden Sie die Vorlage Klassenbibliothek (C#) mit .NET Standard 2.0. Nennen Sie die Projektmappe PetReaderToolTaskExample.

  2. Löschen Sie Class1.cs. Diese Datei wurde automatisch generiert.

  3. Fügen Sie die Microsoft.Build.Utilities.Core-NuGet-Pakete hinzu:

    • Erstellen Sie eine Klasse namens RestApiClientGenerator

    • Erben Sie von ToolTask von MSBuild, und implementieren Sie die abstrakte Methode wie im folgenden Code gezeigt:

      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. Fügen Sie die folgenden Parameter hinzu:

    • InputOpenApiSpec: Speicherort der Spezifikation
    • ClientClassName: Name der generierten Klasse
    • ClientNamespaceName: Namespace, in dem die Klasse generiert wird
    • FolderClientClass: Pfad zu dem Ordner, in dem sich die Klasse befindet
    • NSwagCommandFullPath: vollständiger Pfad zu dem Verzeichnis, in dem sich „NSwag.exe“ befindet
         [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. Installieren Sie das NSwag-Befehlszeilentool. Sie benötigen den vollständigen Pfad zu dem Verzeichnis, in dem sich „NSwag.exe“ befindet.

  6. Implementieren Sie die abstrakten Methoden:

       protected override string ToolName => "RestApiClientGenerator";
    
       protected override string GenerateFullPathToTool()
       {
           return $"{NSwagCommandFullPath}\\NSwag.exe";
       }
    
  7. Es gibt viele Methoden, die Sie überschreiben können. Definieren Sie für die aktuelle Implementierung diese beiden Methoden:

    • Definieren Sie den Befehlsparameter:
      protected override string GenerateCommandLineCommands()
      {
          return $"openapi2csclient /input:{InputOpenApiSpec}  /classname:{ClientClassName} /namespace:{ClientNamespaceName} /output:{FolderClientClass}\\{ClientClassName}.cs";
      }
    
    • Parameterüberprüfung:
    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;
    }
    

    Hinweis

    Diese einfache Überprüfung kann auf andere Weise für die MSBuild-Datei durchgeführt werden. Es wird jedoch empfohlen, dies in C#-Code zu erledigen und den Befehl und die Logik zu kapseln.

  8. Erstellen Sie das Projekt.

Erstellen einer Konsolen-App zur Verwendung des neuen MSBuild-Tasks

Der nächste Schritt besteht darin, eine App zu erstellen, die den Task verwendet.

  1. Erstellen Sie ein Konsolen-App-Projekt, und nennen Sie es PetReaderToolTaskConsoleApp. Wählen Sie .NET 6.0 aus. Markieren Sie es als Startprojekt.

  2. Erstellen Sie ein Klassenbibliotheksprojekt mit dem Namen PetRestApiClient, um den Code zu generieren. Verwenden Sie .NET Standard 2.1.

  3. Erstellen Sie im PetReaderToolTaskConsoleApp-Projekt eine Projektabhängigkeit von PetRestApiClient.

  4. Erstellen Sie im PetRestApiClient-Projekt einen Ordner PetRestApiClient. Dieser Ordner enthält den generierten Code.

  5. Löschen Sie Class1.cs. Diese Datei wurde automatisch generiert.

  6. Fügen Sie in PetRestApiClient die folgenden NuGet-Pakete hinzu:

    • Newtonsoft.Json, das erforderlich ist, um den generierten Client zu kompilieren.
    • System.ComponentModel.Annotations: erforderlich, um den generierten Client zu kompilieren.
  7. Erstellen Sie im PetRestApiClient-Projekt eine Textdatei mit dem Namen petshop-openapi-spec.json (im Projektordner). Um die OpenApi-Spezifikation hinzuzufügen, kopieren Sie den Inhalt von hier in die Datei. Wir möchten einen reproduzierbaren Build erstellen, der nur von der Eingabe abhängt, wie zuvor erläutert. In diesem Beispiel lösen Sie einen Buildfehler aus, wenn ein Benutzer eine URL als Eingabe für die OpenApi-Spezifikation auswählt.

    Wichtig

    Eine allgemeine Neuerstellung funktioniert nicht. Es werden Fehler angezeigt, die darauf hinweisen, dass das Kopieren oder Löschen von „RestApiClientGenerator.dll“ unmöglich ist. Dies liegt daran, dass versucht wird, den benutzerdefinierten MBuild-Task in demselben Buildprozess zu erstellen, der ihn verwendet. Wählen Sie PetReaderToolTaskConsoleApp aus, und erstellen Sie nur dieses Projekt neu. Die andere Lösung besteht darin, den benutzerdefinierten Task in einer vollständig unabhängigen Visual Studio-Projektmappe wie im Beispiel Tutorial: Erstellen eines benutzerdefinierten Tasks zu speichern.

  8. Kopieren Sie den folgenden Code in die Datei 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. Ändern Sie die MSBuild-Anweisungen so, dass der Task aufgerufen und der Code generiert wird. Bearbeiten Sie PetRestApiClient.csproj, indem Sie die folgenden Schritte ausführen:

    1. Registrieren Sie die Verwendung des benutzerdefinierten MSBuild-Tasks:

      <UsingTask TaskName="RestApiClientGenerator.RestApiClientGenerator" AssemblyFile="..\RestApiClientGenerator\bin\Debug\netstandard2.0\RestApiClientGenerator.dll" />
      
    2. Fügen Sie einige Eigenschaften hinzu, die zum Ausführen des Tasks erforderlich sind:

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

      Wichtig

      Wählen Sie den richtigen NSwagCommandFullPath-Wert basierend auf dem Installationsspeicherort in Ihrem System aus.

    3. Fügen Sie ein MSBuild-Ziel hinzu, um den Client während des Buildprozesses zu generieren. Dieses Ziel sollte ausgeführt werden, bevor CoreCompile ausgeführt wird, um den in der Kompilierung verwendeten Code zu generieren.

      <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 und Output beziehen sich auf Inkrementelle Builds, und das forceReGenerationOnRebuild-Ziel löscht die generierte Datei nach CoreClean, wodurch der Client gezwungen wird, während des Neuerstellungsvorgangs neu erstellt zu werden.

  10. Wählen Sie PetReaderToolTaskConsoleApp aus, und erstellen Sie nur dieses Projekt neu. Nun wird der Clientcode generiert und der Code kompiliert. Sie können ihn ausführen und untersuchen, wie er funktioniert. Dieser Code generiert den Code aus einer Datei, und das ist zulässig.

  11. In diesem Schritt veranschaulichen Sie die Parametervalidierung. Ändern Sie in PetRestApiClient.csproj die $(PetClientInputOpenApiSpec)-Eigenschaft, um die URL zu verwenden:

      <PetClientInputOpenApiSpec>https://petstore.swagger.io/v2/swagger.json</PetClientInputOpenApiSpec>
    
  12. Wählen Sie PetReaderToolTaskConsoleApp aus, und erstellen Sie nur dieses Projekt neu. Sie erhalten den Fehler „URL is not allowed“ (URL ist nicht zulässig) gemäß der Entwurfsanforderung.

Laden Sie den Code herunter.

Installieren Sie das NSwag-Befehlszeilentool. Anschließend benötigen Sie den vollständigen Pfad zu dem Verzeichnis, in dem sich „NSwag.exe“ befindet. Bearbeiten Sie anschließend PetRestApiClient.csproj, und wählen Sie den richtigen $(NSwagCommandFullPath)-Wert basierend auf dem Installationspfad auf Ihrem Computer aus. Wählen Sie nun RestApiClientGenerator aus, und erstellen Sie nur dieses Projekt. Wählen Sie schließlich PetReaderToolTaskConsoleApp aus, und erstellen Sie die App neu. Sie können PetReaderToolTaskConsoleApp ausführen, um zu bestätigen, dass alles wie erwartet funktioniert.

Nächste Schritte

Möglicherweise möchten Sie Ihren benutzerdefinierten Task als NuGet-Paket veröffentlichen.

Oder erfahren Sie, wie Sie einen benutzerdefinierten Tasks testen.