Zelfstudie: HTTP-aanvragen maken in een .NET-console-app met behulp van C #
In deze zelfstudie wordt een app gebouwd die HTTP-aanvragen verzendt naar een REST-service op GitHub. De app leest informatie in JSON-indeling en converteert de JSON naar C#-objecten. Het converteren van JSON-naar C#-objecten wordt deserialisatie genoemd.
In de zelfstudie ziet u het volgende:
- HTTP-aanvragen verzenden.
- JSON-antwoorden deserialiseren.
- Configureer deserialisatie met kenmerken.
Als u liever het laatste voorbeeld voor deze zelfstudie volgt, kunt u het downloaden. Zie Voorbeelden en zelfstudies voor downloadinstructies.
Vereisten
- .NET SDK 6.0 of hoger
- Een code-editor zoals [Visual Studio Code (een open-source, platformoverschrijdende editor). U kunt de voorbeeld-app uitvoeren in Windows, Linux of macOS of in een Docker-container.
De client-app maken
Open een opdrachtprompt en maak een nieuwe map voor uw app. Maak hiervan de huidige map.
Typ de volgende opdracht in het consolevenster:
dotnet new console --name WebAPIClient
Met deze opdracht maakt u de startersbestanden voor een eenvoudige Hallo wereld-app. De projectnaam is 'WebAPIClient'.
Navigeer naar de map WebAPIClient en voer de app uit.
cd WebAPIClient
dotnet run
dotnet run
wordt automatisch uitgevoerddotnet restore
om eventuele afhankelijkheden te herstellen die de app nodig heeft. Het wordt ook uitgevoerddotnet build
als dat nodig is. Als het goed is, ziet u de uitvoer van"Hello, World!"
de app. Druk in de terminal op Ctrl+C om de app te stoppen.
HTTP-aanvragen doen
Deze app roept de GitHub-API aan om informatie op te halen over de projecten onder de paraplu van .NET Foundation . Het eindpunt is https://api.github.com/orgs/dotnet/repos. Om informatie op te halen, wordt er een HTTP GET-aanvraag ingediend. Browsers maken ook HTTP GET-aanvragen, zodat u die URL in de adresbalk van uw browser kunt plakken om te zien welke informatie u ontvangt en verwerkt.
Gebruik de HttpClient klasse om HTTP-aanvragen te doen. HttpClient ondersteunt alleen asynchrone methoden voor de langlopende API's. Met de volgende stappen maakt u dus een asynchrone methode en roept u deze aan vanuit de methode Main.
Open het bestand in de
Program.cs
projectmap en vervang de inhoud door het volgende:await ProcessRepositoriesAsync(); static async Task ProcessRepositoriesAsync(HttpClient client) { }
Deze code:
- Hiermee wordt de
Console.WriteLine
-instructie vervangen door een aanroep vanProcessRepositoriesAsync
die hetawait
trefwoord gebruikt. - Hiermee definieert u een lege
ProcessRepositoriesAsync
methode.
- Hiermee wordt de
Gebruik in de
Program
klasse een HttpClient om aanvragen en antwoorden af te handelen door de inhoud te vervangen door de volgende 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) { }
Deze code:
- Http-headers instellen voor alle aanvragen:
- Een
Accept
header om JSON-antwoorden te accepteren - Een
User-Agent
koptekst. Deze headers worden gecontroleerd door de GitHub-servercode en zijn nodig om informatie op te halen uit GitHub.
- Een
- Http-headers instellen voor alle aanvragen:
Roep in de
ProcessRepositoriesAsync
methode het GitHub-eindpunt aan dat een lijst met alle opslagplaatsen onder de .NET Foundation-organisatie retourneert:static async Task ProcessRepositoriesAsync(HttpClient client) { var json = await client.GetStringAsync( "https://api.github.com/orgs/dotnet/repos"); Console.Write(json); }
Deze code:
- Wacht op de taak die is geretourneerd door de aanroepmethode HttpClient.GetStringAsync(String) . Met deze methode wordt een HTTP GET-aanvraag naar de opgegeven URI verzonden. De hoofdtekst van het antwoord wordt geretourneerd als een String, die beschikbaar is wanneer de taak is voltooid.
- De antwoordreeks
json
wordt naar de console afgedrukt.
Bouw de app en voer deze uit.
dotnet run
Er is geen buildwaarschuwing omdat de
ProcessRepositoriesAsync
nu eenawait
operator bevat. De uitvoer is een lange weergave van JSON-tekst.
Het JSON-resultaat deserialiseren
Met de volgende stappen wordt het JSON-antwoord geconverteerd naar C#-objecten. U gebruikt de System.Text.Json.JsonSerializer klasse om JSON te deserialiseren in objecten.
Maak een bestand met de naam Repository.cs en voeg de volgende code toe:
public record class Repository(string name);
De voorgaande code definieert een klasse die het JSON-object vertegenwoordigt dat wordt geretourneerd door de GitHub-API. U gebruikt deze klasse om een lijst met namen van opslagplaatsen weer te geven.
De JSON voor een opslagplaatsobject bevat tientallen eigenschappen, maar alleen de
name
eigenschap wordt gedeserialiseerd. De serializer negeert automatisch JSON-eigenschappen waarvoor geen overeenkomst is in de doelklasse. Met deze functie kunt u eenvoudiger typen maken die werken met slechts een subset velden in een groot JSON-pakket.De C#-conventie is om de eerste letter van eigenschapsnamen een hoofdletter te geven, maar de
name
eigenschap hier begint met een kleine letter, omdat deze precies overeenkomt met wat er in de JSON staat. Later ziet u hoe u C#-eigenschapsnamen gebruikt die niet overeenkomen met de namen van de JSON-eigenschappen.Gebruik de serializer om JSON te converteren naar C#-objecten. Vervang de aanroep in GetStringAsync(String) de
ProcessRepositoriesAsync
methode door de volgende regels:await using Stream stream = await client.GetStreamAsync("https://api.github.com/orgs/dotnet/repos"); var repositories = await JsonSerializer.DeserializeAsync<List<Repository>>(stream);
De bijgewerkte code vervangt GetStringAsync(String) door GetStreamAsync(String). Deze serialisatiemethode gebruikt een stroom in plaats van een tekenreeks als bron.
Het eerste argument voor JsonSerializer.DeserializeAsync<TValue>(Stream, JsonSerializerOptions, CancellationToken) is een
await
expressie.await
expressies kunnen bijna overal in uw code worden weergegeven, ook al hebt u ze tot nu toe alleen gezien als onderdeel van een toewijzingsinstructie. De andere twee parameters,JsonSerializerOptions
enCancellationToken
, zijn optioneel en worden weggelaten in het codefragment.De
DeserializeAsync
methode is algemeen, wat betekent dat u typeargumenten opgeeft voor het soort objecten dat moet worden gemaakt van de JSON-tekst. In dit voorbeeld deserialiseert u naar eenList<Repository>
. Dit is een ander algemeen object, een System.Collections.Generic.List<T>. DeList<T>
klasse slaat een verzameling objecten op. Het argument type declareert het type objecten dat is opgeslagen in deList<T>
. Het argument type is uwRepository
record, omdat de JSON-tekst een verzameling opslagplaatsobjecten vertegenwoordigt.Voeg code toe om de naam van elke opslagplaats weer te geven. Vervang de regels met de volgende tekst:
Console.Write(json);
met de volgende code:
foreach (var repo in repositories ?? Enumerable.Empty<Repository>()) Console.Write(repo.name);
De volgende
using
instructies moeten boven aan het bestand staan:using System.Net.Http.Headers; using System.Text.Json;
Voer de app uit.
dotnet run
De uitvoer is een lijst met de namen van de opslagplaatsen die deel uitmaken van de .NET Foundation.
Deserialisatie configureren
Vervang in Repository.cs de bestandsinhoud door de volgende C#.
using System.Text.Json.Serialization; public record class Repository( [property: JsonPropertyName("name")] string Name);
Deze code:
- Wijzigt de naam van de
name
eigenschap inName
. - Voegt de JsonPropertyNameAttribute toe om op te geven hoe deze eigenschap wordt weergegeven in de JSON.
- Wijzigt de naam van de
Werk in Program.cs de code bij om het nieuwe hoofdlettergebruik van de
Name
eigenschap te gebruiken:foreach (var repo in repositories) Console.Write(repo.Name);
Voer de app uit.
De uitvoer is hetzelfde.
De code herstructureren
De ProcessRepositoriesAsync
methode kan het asynchrone werk doen en een verzameling van de opslagplaatsen retourneren. Wijzig die methode om te retourneren Task<List<Repository>>
en verplaats de code die naar de console schrijft in de buurt van de aanroeper.
Wijzig de handtekening van
ProcessRepositoriesAsync
om een taak te retourneren waarvan het resultaat een lijstRepository
met objecten is:static async Task<List<Repository>> ProcessRepositoriesAsync(HttpClient client)
Retourneer de opslagplaatsen na het verwerken van het JSON-antwoord:
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();
De compiler genereert het
Task<T>
-object voor de retourwaarde omdat u deze methode hebt gemarkeerd alsasync
.Wijzig het bestand Program.cs en vervang de aanroep naar
ProcessRepositoriesAsync
door het volgende om de resultaten vast te leggen en de naam van elke opslagplaats naar de console te schrijven.var repositories = await ProcessRepositoriesAsync(client); foreach (var repo in repositories) Console.Write(repo.Name);
Voer de app uit.
De uitvoer is hetzelfde.
Meer eigenschappen deserialiseren
Met de volgende stappen voegt u code toe om meer eigenschappen in het ontvangen JSON-pakket te verwerken. U wilt waarschijnlijk niet elke eigenschap verwerken, maar als u er nog een paar toevoegt, ziet u andere functies van C#.
Vervang de inhoud van
Repository
klasse door de volgenderecord
definitie: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);
De Uri typen en
int
hebben ingebouwde functionaliteit om te converteren naar en van tekenreeksweergave. Er is geen extra code nodig om te deserialiseren van de JSON-tekenreeksindeling naar deze doeltypen. Als het JSON-pakket gegevens bevat die niet worden geconverteerd naar een doeltype, genereert de serialisatieactie een uitzondering.Werk de
foreach
lus in het bestand Program.cs bij om de eigenschapswaarden weer te geven: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(); }
Voer de app uit.
De lijst bevat nu de aanvullende eigenschappen.
Een datumeigenschap toevoegen
De datum van de laatste pushbewerking wordt op deze manier opgemaakt in het JSON-antwoord:
2016-02-08T21:27:00Z
Deze indeling is voor Coordinated Universal Time (UTC), dus het resultaat van deserialisatie is een DateTime waarde waarvan Kind de eigenschap is Utc.
Als u een datum en tijd wilt weergeven in uw tijdzone, moet u een aangepaste conversiemethode schrijven.
Voeg in Repository.cs een eigenschap toe voor de UTC-weergave van de datum en tijd en een eigenschap readonly
LastPush
die de datum retourneert die is geconverteerd naar de lokale tijd. Het bestand moet er als volgt uitzien: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(); }
De
LastPush
eigenschap wordt gedefinieerd met behulp van een expressie-bodied lid voor deget
accessor. Er is geenset
toegangsbeheer. Het weglaten van deset
accessor is een manier om een eigenschap met het kenmerk Alleen-lezen in C# te definiƫren. (Ja, u kunt alleen-schrijven-eigenschappen maken in C#, maar de waarde ervan is beperkt.)Voeg nog een uitvoerinstructie toe in Program.cs: opnieuw:
Console.WriteLine($"Last push: {repo.LastPush}");
De volledige app moet lijken op het volgende Program.cs-bestand :
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(); }
Voer de app uit.
De uitvoer bevat de datum en tijd van de laatste push naar elke opslagplaats.
Volgende stappen
In deze zelfstudie hebt u een app gemaakt die webaanvragen doet en de resultaten parseert. Uw versie van de app moet nu overeenkomen met het voltooide voorbeeld.
Meer informatie over het configureren van JSON-serialisatie vindt u in JSON serialiseren en deserialiseren (marshal en unmarshal) in .NET.