Delen via


Zelfstudie: HTTP-aanvragen maken in een .NET-console-app met behulp van C#

In deze zelfstudie wordt een app gebouwd waarmee HTTP-aanvragen worden verzonden naar een REST-service op GitHub. De app leest informatie in JSON-indeling en converteert de JSON naar C#-objecten. Converteren van JSON naar C#-objecten wordt deserialisatie genoemd.

In de zelfstudie ziet u hoe u het volgende kunt doen:

  • 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 zelfstudiesvoor downloadinstructies.

Vereiste voorwaarden

De client-app maken

  1. Open een opdrachtprompt en maak een nieuwe map voor uw app. Maak dat de huidige map.

  2. Voer de volgende opdracht in een consolevenster in:

    dotnet new console --name WebAPIClient
    

    Met deze opdracht maakt u de startersbestanden voor een eenvoudige 'Hallo wereld'-app. De projectnaam is 'WebAPIClient'.

  3. Navigeer naar de map WebAPIClient en voer de app uit.

    cd WebAPIClient
    
    dotnet run
    

    dotnet run wordt automatisch uitgevoerd dotnet restore om afhankelijkheden te herstellen die de app nodig heeft. Het wordt ook uitgevoerd dotnet build indien nodig. U ziet nu de uitvoer "Hello, World!"van de app. Druk in de terminal op Ctrl+C om de app te stoppen.

HTTP-aanvragen maken

Met deze app wordt de GitHub-API aangeroepen voor informatie over de projecten onder de paraplu van .NET Foundation . Het eindpunt is https://api.github.com/orgs/dotnet/repos. Als u informatie wilt ophalen, 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 maken. 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 Main-methode.

  1. Open het Program.cs bestand in de projectmap en vervang de inhoud door het volgende:

    await ProcessRepositoriesAsync();
    
    static async Task ProcessRepositoriesAsync(HttpClient client)
    {
    }
    

    Deze code:

    • Vervangt de Console.WriteLine instructie door een aanroep naar ProcessRepositoriesAsync die gebruikmaakt van het await trefwoord.
    • Definieert een lege ProcessRepositoriesAsync methode.
  2. Gebruik in de Program klasse een HttpClient om aanvragen en antwoorden te verwerken 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:

    • Hiermee stelt u HTTP-headers in voor alle aanvragen:
      • Een Accept header voor het accepteren van JSON-antwoorden
      • Een User-Agent koptekst. Deze headers worden gecontroleerd door de GitHub-servercode en zijn nodig om informatie op te halen uit GitHub.
  3. Roep in de ProcessRepositoriesAsync methode het GitHub-eindpunt aan dat een lijst met alle opslagplaatsen retourneert onder de .NET Foundation-organisatie:

     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 verzonden naar de opgegeven URI. De hoofdtekst van het antwoord wordt geretourneerd als een String, die beschikbaar is wanneer de taak is voltooid.
    • De antwoordtekenreeks json wordt afgedrukt naar de console.
  4. Bouw de app en voer deze uit.

    dotnet run
    

    Er is geen buildwaarschuwing omdat de ProcessRepositoriesAsync operator nu bevat await . De uitvoer is een lange weergave van JSON-tekst.

Het JSON-resultaat deserialiseren

De volgende stappen vereenvoudigen de aanpak voor het ophalen van de gegevens en het verwerken ervan. U gebruikt de GetFromJsonAsync extensiemethode die deel uitmaakt van het 📦 NuGet-pakket System.Net.Http.Json om de JSON-resultaten in objecten op te halen en deserialiseren.

  1. 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 alleen werken met een subset velden in een groot JSON-pakket.

    Hoewel de GetFromJsonAsync methode die u in het volgende punt gaat gebruiken, een voordeel heeft dat het hoofdlettergevoelig is als het gaat om eigenschapsnamen, is de C#-conventie het hoofdlettergebruik van de eerste letter van eigenschapsnamen.

  2. Gebruik de HttpClientJsonExtensions.GetFromJsonAsync methode om JSON op te halen en te converteren naar C#-objecten. Vervang de aanroep in GetStringAsync(String) de ProcessRepositoriesAsync methode door de volgende regels:

    var repositories = await client.GetFromJsonAsync<List<Repository>>("https://api.github.com/orgs/dotnet/repos");
    

    De bijgewerkte code vervangt door GetStringAsync(String)HttpClientJsonExtensions.GetFromJsonAsync.

    Het eerste argument voor GetFromJsonAsync de methode is een await expressie. await expressies kunnen bijna overal in uw code worden weergegeven, ook al hebt u deze tot nu toe alleen gezien als onderdeel van een toewijzingsinstructie. De volgende parameter is requestUri optioneel en hoeft niet te worden opgegeven als al is opgegeven bij het maken van het client object. U hebt het client object niet opgegeven met de URI waarnaar u een aanvraag wilt verzenden, dus u hebt de URI nu opgegeven. De laatste optionele parameter wordt CancellationToken weggelaten in het codefragment.

    De GetFromJsonAsync methode is algemeen. Dit betekent dat u typeargumenten opgeeft voor het soort objecten dat moet worden gemaakt op basis van de opgehaalde JSON-tekst. In dit voorbeeld gaat u deserialiseren naar een List<Repository>, een ander algemeen object, een System.Collections.Generic.List<T>. In de List<T> klasse wordt een verzameling objecten opgeslagen. Het typeargument declareert het type objecten dat is opgeslagen in de List<T>. Het typeargument is uw Repository record, omdat de JSON-tekst een verzameling opslagplaatsobjecten vertegenwoordigt.

  3. Voeg code toe om de naam van elke opslagplaats weer te geven. Vervang de regels die worden gelezen:

    Console.Write(json);
    

    met de volgende code:

    foreach (var repo in repositories ?? Enumerable.Empty<Repository>())
        Console.WriteLine(repo.Name);
    
  4. De volgende using instructies moeten boven aan het bestand aanwezig zijn:

    using System.Net.Http.Headers;
    using System.Net.Http.Json;
    
  5. Voer de app uit.

    dotnet run
    

    De uitvoer is een lijst met de namen van de opslagplaatsen die deel uitmaken van de .NET Foundation.

De code herstructureren

De ProcessRepositoriesAsync methode kan het asynchrone werk uitvoeren en een verzameling van de opslagplaatsen retourneren. Wijzig deze methode om deze te retourneren Task<List<Repository>>en verplaats de code die naar de console schrijft in de buurt van de aanroeper.

  1. Wijzig de handtekening van het retourneren van ProcessRepositoriesAsync een taak waarvan het resultaat een lijst Repository met objecten is:

    static async Task<List<Repository>> ProcessRepositoriesAsync(HttpClient client)
    
  2. Retourneert de opslagplaatsen na het verwerken van het JSON-antwoord:

    var repositories = await client.GetFromJsonAsync<List<Repository>>("https://api.github.com/orgs/dotnet/repos");
    return repositories ?? new();
    

    De compiler genereert het Task<T> object voor de retourwaarde omdat u deze methode hebt gemarkeerd als async.

  3. Wijzig het Program.cs-bestand , waarbij u de aanroep vervangt door ProcessRepositoriesAsync het volgende om de resultaten vast te leggen en elke naam van de opslagplaats naar de console te schrijven.

    var repositories = await ProcessRepositoriesAsync(client);
    
    foreach (var repo in repositories)
        Console.WriteLine(repo.Name);
    
  4. Voer de app uit.

    De uitvoer is hetzelfde.

Meer eigenschappen deserialiseren

In de volgende stappen breiden we de code uit om meer eigenschappen te verwerken van de JSON-nettolading die wordt geretourneerd door de GitHub-API. U hoeft waarschijnlijk niet elke eigenschap te verwerken, maar door er een paar toe te voegen, kunt u extra C#-functies demonstreren.

  1. Vervang de inhoud van de Repository klasse door de volgende record definitie. Zorg ervoor dat u de System.Text.Json.Serialization naamruimte importeert en het [JsonPropertyName] kenmerk toepast om JSON-velden expliciet toe te wijzen aan C#-eigenschappen.

     using System.Text.Json.Serialization;
    
     public record class Repository(
       string Name,
       string Description,
       [property: JsonPropertyName("html_url")] Uri GitHubHomeUrl,
       Uri Homepage,
       int Watchers,
       [property: JsonPropertyName("pushed_at")] DateTime LastPushUtc
      );
    

    De Uri en int typen hebben ingebouwde functionaliteit om te converteren naar en van tekenreeksweergave. Er is geen extra code nodig om deserialiseren van JSON-tekenreeksindeling naar deze doeltypen. Als het JSON-pakket gegevens bevat die niet naar een doeltype worden geconverteerd, genereert de serialisatieactie een uitzondering.

    JSON gebruikt lowercase vaak of snake_case voor eigenschapsnamen. Velden zoals html_url en pushed_at volgen niet de PascalCase-naamconventies van C#. Het gebruik [JsonPropertyName] zorgt ervoor dat deze JSON-sleutels correct zijn gebonden aan de bijbehorende C#-eigenschappen, zelfs als hun namen verschillen in het geval of onderstrepingstekens bevatten. Deze aanpak garandeert voorspelbare en stabiele deserialisatie, terwijl PascalCase-eigenschapsnamen in C# worden toegestaan. Daarnaast is GetFromJsonAsync de case-insensitive methode wanneer overeenkomende eigenschapsnamen worden gebruikt, zodat er geen verdere conversie nodig is.

  2. Werk de foreach lus in het Program.cs bestand 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();
    }
    
  3. 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 notatie is bedoeld 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 ophalen die in uw tijdzone wordt weergegeven, moet u een aangepaste conversiemethode schrijven.

  1. Voeg in Repository.cs een eigenschap toe voor de UTC-weergave van de datum en tijd en een alleen-lezen LastPush eigenschap die de datum retourneert die wordt geconverteerd naar lokale tijd. Het bestand moet er als volgt uitzien:

    using System.Text.Json.Serialization;
    
    public record class Repository(
        string Name,
        string Description,
        [property: JsonPropertyName("html_url")] Uri GitHubHomeUrl,
        Uri Homepage,
        int Watchers,
        [property: JsonPropertyName("pushed_at")] DateTime LastPushUtc
        )
    {
        public DateTime LastPush => LastPushUtc.ToLocalTime();
    }
    

    De LastPush eigenschap wordt gedefinieerd met behulp van een expressie-lichaamslid voor de get toegangsfunctie. Er is geen set toegangsrechten. Het weglaten van de set accessor is één manier om een alleen-lezen eigenschap in C# te definiëren. (Ja, u kunt eigenschappen voor alleen-schrijven maken in C#, maar hun waarde is beperkt.)

  2. Voeg nog een uitvoerinstructie toe in Program.cs: opnieuw:

    Console.WriteLine($"Last push: {repo.LastPush}");
    
  3. De volledige app moet er ongeveer uitzien als het volgende Program.cs bestand:

    using System.Net.Http.Headers;
    using System.Net.Http.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)
    {
        var repositories = await client.GetFromJsonAsync<List<Repository>>("https://api.github.com/orgs/dotnet/repos");
        return repositories ?? new List<Repository>();
    }
    
  4. 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 waarmee webaanvragen worden gedaan en de resultaten worden geparseerd. Uw versie van de app moet nu overeenkomen met het voltooide voorbeeld.

Meer informatie over het configureren van JSON-serialisatie in JSON in .NET: serialiseren en deserialiseren (marshal en unmarshal).