Självstudie: Göra HTTP-begäranden i en .NET-konsolapp med C #
Den här självstudien skapar en app som utfärdar HTTP-begäranden till en REST-tjänst på GitHub. Appen läser information i JSON-format och konverterar JSON till C#-objekt. Konvertering från JSON till C#-objekt kallas deserialisering.
Självstudien visar hur du:
- Skicka HTTP-begäranden.
- Deserialisera JSON-svar.
- Konfigurera deserialisering med attribut.
Om du föredrar att följa med i det slutliga exemplet för den här självstudien kan du ladda ned det. Instruktioner för nedladdning finns i Exempel och självstudier.
Krav
- .NET SDK 6.0 eller senare
- En kodredigerare som [Visual Studio Code (en plattformsoberoende redigerare med öppen källkod). Du kan köra exempelappen i Windows, Linux eller macOS eller i en Docker-container.
Skapa klientappen
Öppna en kommandotolk och skapa en ny katalog för din app. Gör det till den aktuella katalogen.
Ange följande kommando i ett konsolfönster:
dotnet new console --name WebAPIClient
Det här kommandot skapar startfilerna för en grundläggande "Hello World"-app. Projektnamnet är "WebAPIClient".
Navigera till katalogen "WebAPIClient" och kör appen.
cd WebAPIClient
dotnet run
dotnet run
körsdotnet restore
automatiskt för att återställa eventuella beroenden som appen behöver. Den körsdotnet build
också om det behövs. Du bör se appens utdata"Hello, World!"
. Tryck på Ctrl+C i terminalen för att stoppa appen.
Göra HTTP-begäranden
Den här appen anropar GitHub-API :et för att få information om projekten under .NET Foundation-paraplyet . Slutpunkten är https://api.github.com/orgs/dotnet/repos. För att hämta information gör den en HTTP GET-begäran. Webbläsare gör också HTTP GET-begäranden, så du kan klistra in webbadressen i webbläsarens adressfält för att se vilken information du kommer att ta emot och bearbeta.
HttpClient Använd klassen för att göra HTTP-begäranden. HttpClient stöder endast asynkrona metoder för dess långvariga API:er. Så följande steg skapar en asynkron metod och anropar den från Main-metoden.
Öppna filen i projektkatalogen
Program.cs
och ersätt dess innehåll med följande:await ProcessRepositoriesAsync(); static async Task ProcessRepositoriesAsync(HttpClient client) { }
Den här koden:
- Ersätter -instruktionen
Console.WriteLine
med ett anrop tillProcessRepositoriesAsync
som använder nyckelordetawait
. - Definierar en tom
ProcessRepositoriesAsync
metod.
- Ersätter -instruktionen
Program
I klassen använder du en HttpClient för att hantera begäranden och svar genom att ersätta innehållet med följande C#.using System.Net.Http.Headers; using HttpClient client = new(); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json")); client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter"); await ProcessRepositoriesAsync(client); static async Task ProcessRepositoriesAsync(HttpClient client) { }
Den här koden:
- Konfigurerar HTTP-huvuden för alla begäranden:
- Ett
Accept
sidhuvud för att acceptera JSON-svar - En
User-Agent
rubrik. Dessa huvuden kontrolleras av GitHub-serverkoden och är nödvändiga för att hämta information från GitHub.
- Ett
- Konfigurerar HTTP-huvuden för alla begäranden:
ProcessRepositoriesAsync
I metoden anropar du GitHub-slutpunkten som returnerar en lista över alla lagringsplatser under .NET Foundation-organisationen:static async Task ProcessRepositoriesAsync(HttpClient client) { var json = await client.GetStringAsync( "https://api.github.com/orgs/dotnet/repos"); Console.Write(json); }
Den här koden:
- Väntar på uppgiften som returneras från anropande HttpClient.GetStringAsync(String) metod. Den här metoden skickar en HTTP GET-begäran till den angivna URI:n. Brödtexten i svaret returneras som en String, som är tillgänglig när uppgiften slutförs.
- Svarssträngen
json
skrivs ut till konsolen.
Skapa appen och kör den.
dotnet run
Det finns ingen byggvarning eftersom nu
ProcessRepositoriesAsync
innehåller enawait
operator. Utdata är en lång visning av JSON-text.
Deserialisera JSON-resultatet
Följande steg konverterar JSON-svaret till C#-objekt. Du använder System.Text.Json.JsonSerializer klassen för att deserialisera JSON till objekt.
Skapa en fil med namnet Repository.cs och lägg till följande kod:
public record class Repository(string name);
Koden ovan definierar en klass som representerar JSON-objektet som returneras från GitHub-API:et. Du använder den här klassen för att visa en lista över lagringsplatsnamn.
JSON för ett lagringsplatsobjekt innehåller dussintals egenskaper, men endast
name
egenskapen deserialiseras. Serialiseraren ignorerar automatiskt JSON-egenskaper för vilka det inte finns någon matchning i målklassen. Den här funktionen gör det enklare att skapa typer som endast fungerar med en delmängd av fälten i ett stort JSON-paket.C#-konventionen är att kapitalisera den första bokstaven i egenskapsnamn, men egenskapen här börjar med en gemen
name
bokstav eftersom den matchar exakt vad som finns i JSON. Senare får du se hur du använder C#-egenskapsnamn som inte matchar JSON-egenskapsnamnen.Använd serialiseraren för att konvertera JSON till C#-objekt. Ersätt anropet till GetStringAsync(String) i
ProcessRepositoriesAsync
metoden med följande rader:await using Stream stream = await client.GetStreamAsync("https://api.github.com/orgs/dotnet/repos"); var repositories = await JsonSerializer.DeserializeAsync<List<Repository>>(stream);
Den uppdaterade koden ersätter GetStringAsync(String) med GetStreamAsync(String). Den här serialiserarmetoden använder en ström i stället för en sträng som källa.
Det första argumentet till JsonSerializer.DeserializeAsync<TValue>(Stream, JsonSerializerOptions, CancellationToken) är ett
await
uttryck.await
-uttryck kan visas nästan var som helst i koden, även om du hittills bara har sett dem som en del av en tilldelningsinstruktor. De andra två parametrarna,JsonSerializerOptions
ochCancellationToken
, är valfria och utelämnas i kodfragmentet.Metoden
DeserializeAsync
är allmän, vilket innebär att du anger typargument för vilken typ av objekt som ska skapas från JSON-texten. I det här exemplet avserialiserar du till ett , som är ettList<Repository>
annat allmänt objekt, ett System.Collections.Generic.List<T>. KlassenList<T>
lagrar en samling objekt. Typargumentet deklarerar typen av objekt som lagras iList<T>
. Typargumentet är dinRepository
post eftersom JSON-texten representerar en samling lagringsplatsobjekt.Lägg till kod för att visa namnet på varje lagringsplats. Ersätt raderna som lyder:
Console.Write(json);
med följande kod:
foreach (var repo in repositories ?? Enumerable.Empty<Repository>()) Console.Write(repo.name);
Följande
using
direktiv bör finnas överst i filen:using System.Net.Http.Headers; using System.Text.Json;
Kör appen.
dotnet run
Utdata är en lista över namnen på de lagringsplatser som ingår i .NET Foundation.
Konfigurera deserialisering
I Repository.cs ersätter du filinnehållet med följande C#.
using System.Text.Json.Serialization; public record class Repository( [property: JsonPropertyName("name")] string Name);
Den här koden:
- Ändrar namnet på
name
egenskapen tillName
. - JsonPropertyNameAttribute Lägger till för att ange hur den här egenskapen ska visas i JSON.
- Ändrar namnet på
I Program.cs uppdaterar du koden så att den använder egenskapens
Name
nya versaler:foreach (var repo in repositories) Console.Write(repo.Name);
Kör appen.
Utdata är desamma.
Omstrukturera koden
Metoden ProcessRepositoriesAsync
kan utföra asynkront arbete och returnera en samling lagringsplatser. Ändra metoden för att returnera Task<List<Repository>>
och flytta koden som skriver till konsolen nära anroparen.
Ändra signaturen
ProcessRepositoriesAsync
för att returnera en aktivitet vars resultat är en lista medRepository
objekt:static async Task<List<Repository>> ProcessRepositoriesAsync(HttpClient client)
Returnera lagringsplatserna efter bearbetning av JSON-svaret:
await using Stream stream = await client.GetStreamAsync("https://api.github.com/orgs/dotnet/repos"); var repositories = await JsonSerializer.DeserializeAsync<List<Repository>>(stream); return repositories ?? new();
Kompilatorn genererar
Task<T>
objektet för returvärdet eftersom du har markerat den här metoden somasync
.Ändra filen Program.cs och ersätt anropet till
ProcessRepositoriesAsync
med följande för att samla in resultatet och skriva varje lagringsplatsnamn till konsolen.var repositories = await ProcessRepositoriesAsync(client); foreach (var repo in repositories) Console.Write(repo.Name);
Kör appen.
Utdata är desamma.
Deserialisera fler egenskaper
Följande steg lägger till kod för att bearbeta fler av egenskaperna i det mottagna JSON-paketet. Du vill förmodligen inte bearbeta alla egenskaper, men om du lägger till några fler visas andra funktioner i C#.
Ersätt innehållet i
Repository
klassen med följanderecord
definition:using System.Text.Json.Serialization; public record class Repository( [property: JsonPropertyName("name")] string Name, [property: JsonPropertyName("description")] string Description, [property: JsonPropertyName("html_url")] Uri GitHubHomeUrl, [property: JsonPropertyName("homepage")] Uri Homepage, [property: JsonPropertyName("watchers")] int Watchers);
Typerna Uri och
int
har inbyggda funktioner för att konvertera till och från strängrepresentation. Ingen extra kod behövs för att deserialisera från JSON-strängformat till dessa måltyper. Om JSON-paketet innehåller data som inte konverteras till en måltyp utlöser serialiseringsåtgärden ett undantag.Uppdatera loopen
foreach
i filen Program.cs för att visa egenskapsvärdena:foreach (var repo in repositories) { Console.WriteLine($"Name: {repo.Name}"); Console.WriteLine($"Homepage: {repo.Homepage}"); Console.WriteLine($"GitHub: {repo.GitHubHomeUrl}"); Console.WriteLine($"Description: {repo.Description}"); Console.WriteLine($"Watchers: {repo.Watchers:#,0}"); Console.WriteLine(); }
Kör appen.
Listan innehåller nu de ytterligare egenskaperna.
Lägg till en datumegenskap
Datumet för den senaste push-åtgärden formateras på det här sättet i JSON-svaret:
2016-02-08T21:27:00Z
Det här formatet är för Coordinated Universal Time (UTC), så resultatet av deserialisering är ett DateTime värde vars Kind egenskap är Utc.
För att få ett datum och en tid som representeras i tidszonen måste du skriva en anpassad konverteringsmetod.
I Repository.cs lägger du till en egenskap för UTC-representationen av datum och tid och en skrivskyddad
LastPush
egenskap som returnerar det datum som konverterats till lokal tid. Filen bör se ut så här:using System.Text.Json.Serialization; public record class Repository( [property: JsonPropertyName("name")] string Name, [property: JsonPropertyName("description")] string Description, [property: JsonPropertyName("html_url")] Uri GitHubHomeUrl, [property: JsonPropertyName("homepage")] Uri Homepage, [property: JsonPropertyName("watchers")] int Watchers, [property: JsonPropertyName("pushed_at")] DateTime LastPushUtc) { public DateTime LastPush => LastPushUtc.ToLocalTime(); }
Egenskapen
LastPush
definieras med hjälp av en expression-bodied medlem förget
accessorn. Det finns ingenset
accessor. Attset
utelämna accessorn är ett sätt att definiera en skrivskyddad egenskap i C#. (Ja, du kan skapa skrivskyddade egenskaper i C#, men deras värde är begränsat.)Lägg till ytterligare en utdatasats i Program.cs: igen:
Console.WriteLine($"Last push: {repo.LastPush}");
Den fullständiga appen bör likna följande Program.cs-fil :
using System.Net.Http.Headers; using System.Text.Json; using HttpClient client = new(); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json")); client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter"); var repositories = await ProcessRepositoriesAsync(client); foreach (var repo in repositories) { Console.WriteLine($"Name: {repo.Name}"); Console.WriteLine($"Homepage: {repo.Homepage}"); Console.WriteLine($"GitHub: {repo.GitHubHomeUrl}"); Console.WriteLine($"Description: {repo.Description}"); Console.WriteLine($"Watchers: {repo.Watchers:#,0}"); Console.WriteLine($"{repo.LastPush}"); Console.WriteLine(); } static async Task<List<Repository>> ProcessRepositoriesAsync(HttpClient client) { await using Stream stream = await client.GetStreamAsync("https://api.github.com/orgs/dotnet/repos"); var repositories = await JsonSerializer.DeserializeAsync<List<Repository>>(stream); return repositories ?? new(); }
Kör appen.
Utdata innehåller datum och tid för den senaste push-överföringen till varje lagringsplats.
Nästa steg
I den här självstudien har du skapat en app som gör webbbegäranden och parsar resultatet. Din version av appen bör nu matcha det färdiga exemplet.
Läs mer om hur du konfigurerar JSON-serialisering i Serialisera och deserialisera (marskalk och omarshal) JSON i .NET.