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.
Skapa ett nytt konsolprogram med namnet
PetReaderExecTaskExample
. Använd .NET 6.0 eller senare.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.I
PetReaderExecTaskExample
projektet, och lägg till ett projektberoende iPetShopRestClient
projektet.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
I
PetShopRestClient
-projektet lägger du till en mapp (med namnetPetShopRestClient
) för kodgenereringen och tar bort Class1.cs som genererades automatiskt.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.
Ä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 uppgiftenExec
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 tillConsoleToMsBuild="true"
i taggen<Exec>
och sedan samla in utdata med parameternConsoleOutput
i en<Output>
tagg.ConsoleOutput
returnerar utdata som enItem
. Mellanrum tas bort.ConsoleOutput
aktiveras närConsoleToMSBuild
ä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ålCoreClean
.Kör en återskapning av Visual Studio-lösningen och se klienten som genereras i mappen
PetShopRestClient
.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ändaHttpClientFactory
för att skapa ettHttpClient
objekt som åtgärdar kända problem medHttpClient
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.
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 namnetPetReaderToolTaskExample
.Ta bort Class1.cs, som genererades automatiskt.
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(); } } }
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; }
Installera kommandoradsverktyget NSwag. Du behöver den fullständiga sökvägen till katalogen där NSwag.exe finns.
Implementera abstrakta metoder:
protected override string ToolName => "RestApiClientGenerator"; protected override string GenerateFullPathToTool() { return $"{NSwagCommandFullPath}\\NSwag.exe"; }
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.
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.
Skapa ett konsolapp-projekt och ge det namnet
PetReaderToolTaskConsoleApp
. Välj .NET 6.0. Markera det som startprojekt.Skapa ett klassbibliotek projekt för att generera koden, med namnet
PetRestApiClient
. Använd .NET Standard 2.1.I
PetReaderToolTaskConsoleApp
-projektet skapar du ett projektberoende tillPetRestApiClient
.I
PetRestApiClient
-projektet skapar du en mappPetRestApiClient
. Den här mappen innehåller den genererade koden.Ta bort Class1.cs, som genererades automatiskt.
På
PetRestApiClient
lä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
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äljPetReaderToolTaskConsoleApp
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.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}"); } } }
Ändra MSBuild-instruktionerna för att anropa uppgiften och generera koden. Redigera PetRestApiClient.csproj genom att följa dessa steg:
Registrera användningen av den anpassade MSBuild-uppgiften:
<UsingTask TaskName="RestApiClientGenerator.RestApiClientGenerator" AssemblyFile="..\RestApiClientGenerator\bin\Debug\netstandard2.0\RestApiClientGenerator.dll" />
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.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
ochOutput
är relaterade till inkrementell kompilering, och måletforceReGenerationOnRebuild
tar bort den genererade filen efterCoreClean
, vilket tvingar klienten att återskapas under omkompileringen.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.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>
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 PetReaderToolTaskConsoleApp
och å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.