Freigeben über


Lernprogramm: Durchführen von HTTP-Anforderungen in einer .NET-Konsolen-App mit C#

In diesem Lernprogramm wird eine App erstellt, die HTTP-Anforderungen an einen REST-Dienst auf GitHub ausgibt. Die App liest Informationen im JSON-Format und konvertiert den JSON-Code in C#-Objekte. Das Konvertieren von JSON in C#-Objekte wird als Deserialisierung bezeichnet.

Das Lernprogramm zeigt, wie Sie:

  • HTTP-Anforderungen senden.
  • Json-Antworten deserialisieren.
  • Konfigurieren Sie die Deserialisierung mit Attributen.

Wenn Sie es lieber zusammen mit dem endgültigen Beispiel für dieses Lernprogramm befolgen möchten, können Sie es herunterladen. Anweisungen zum Herunterladen finden Sie unter Beispiele und Lernprogramme.

Voraussetzungen

Erstellen der Client-App

  1. Öffnen Sie eine Eingabeaufforderung, und erstellen Sie ein neues Verzeichnis für Ihre App. Stellen Sie sicher, dass das aktuelle Verzeichnis ist.

  2. Geben Sie den folgenden Befehl in ein Konsolenfenster ein:

    dotnet new console --name WebAPIClient
    

    Mit diesem Befehl werden die Startdateien für eine einfache "Hello World"-App erstellt. Der Projektname lautet "WebAPIClient".

  3. Navigieren Sie zum Verzeichnis "WebAPIClient", und führen Sie die App aus.

    cd WebAPIClient
    
    dotnet run
    

    dotnet run wird automatisch ausgeführt dotnet restore , um abhängigkeiten wiederherzustellen, die die App benötigt. Sie wird auch bei Bedarf ausgeführt dotnet build . Die App-Ausgabe "Hello, World!"sollte angezeigt werden. Drücken Sie in Ihrem Terminal STRG+C , um die App zu beenden.

Übermitteln von HTTP-Anforderungen

Diese App ruft die GitHub-API auf, um Informationen zu den Projekten unter dem .NET Foundation-Dach abzurufen. Der Endpunkt ist https://api.github.com/orgs/dotnet/repos. Um Informationen abzurufen, wird eine HTTP GET-Anforderung gestellt. Browser stellen auch HTTP GET-Anforderungen, sodass Sie diese URL in ihre Browseradressleiste einfügen können, um zu sehen, welche Informationen Sie empfangen und verarbeiten werden.

Verwenden Sie die HttpClient Klasse, um HTTP-Anforderungen zu stellen. HttpClient unterstützt nur asynchrone Methoden für die langfristig ausgeführten APIs. Die folgenden Schritte erstellen also eine asynchrone Methode und rufen sie aus der Main-Methode auf.

  1. Öffnen Sie die Program.cs Datei im Projektverzeichnis, und ersetzen Sie deren Inhalt durch Folgendes:

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

    Dieser Code:

    • Ersetzt die Console.WriteLine Anweisung durch einen Aufruf, der ProcessRepositoriesAsync das await Schlüsselwort verwendet.
    • Definiert eine leere ProcessRepositoriesAsync Methode.
  2. Verwenden Sie in der Program Klasse eine HttpClient Zum Behandeln von Anforderungen und Antworten, indem Sie den Inhalt durch den folgenden C# ersetzen.

    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)
    {
    }
    

    Dieser Code:

    • Richtet HTTP-Header für alle Anforderungen ein:
      • Ein Accept Header zum Akzeptieren von JSON-Antworten
      • Eine User-Agent Kopfzeile. Diese Header werden vom GitHub-Servercode überprüft und sind erforderlich, um Informationen von GitHub abzurufen.
  3. Rufen Sie in der ProcessRepositoriesAsync Methode den GitHub-Endpunkt auf, der eine Liste aller Repositorys unter der .NET Foundation-Organisation zurückgibt:

     static async Task ProcessRepositoriesAsync(HttpClient client)
     {
         var json = await client.GetStringAsync(
             "https://api.github.com/orgs/dotnet/repos");
    
         Console.Write(json);
     }
    

    Dieser Code:

    • Erwartet die von der aufrufenden HttpClient.GetStringAsync(String) Methode zurückgegebene Aufgabe. Diese Methode sendet eine HTTP GET-Anforderung an den angegebenen URI. Der Textkörper der Antwort wird als ein String, das verfügbar ist, wenn die Aufgabe abgeschlossen ist.
    • Die Antwortzeichenfolge json wird auf die Konsole gedruckt.
  4. Erstellen Sie die App, und führen Sie sie aus.

    dotnet run
    

    Es gibt keine Buildwarnung, da die ProcessRepositoriesAsync jetzt einen await Operator enthält. Die Ausgabe ist eine lange Anzeige von JSON-Text.

Deserialisieren des JSON-Ergebnisses

Die folgenden Schritte vereinfachen den Ansatz zum Abrufen der Daten und deren Verarbeitung. Sie verwenden die GetFromJsonAsync Erweiterungsmethode, die Teil des 📦 Pakets "System.Net.Http.Json NuGet" ist, um die JSON-Ergebnisse in Objekte abzurufen und deserialisieren.

  1. Erstellen Sie eine Datei mit dem Namen Repository.cs , und fügen Sie den folgenden Code hinzu:

    public record class Repository(string Name);
    

    Der vorangehende Code definiert eine Klasse, die das JSON-Objekt darstellt, das von der GitHub-API zurückgegeben wird. Sie verwenden diese Klasse, um eine Liste der Repositorynamen anzuzeigen.

    Der JSON-Code für ein Repositoryobjekt enthält Dutzende von Eigenschaften, aber nur die Name Eigenschaft wird deserialisiert. Der Serialisierer ignoriert automatisch JSON-Eigenschaften, für die keine Übereinstimmung in der Zielklasse vorhanden ist. Dieses Feature erleichtert das Erstellen von Typen, die nur mit einer Teilmenge von Feldern in einem großen JSON-Paket funktionieren.

    Obwohl die Methode, die GetFromJsonAsync Sie im nächsten Punkt verwenden, die Groß-/Kleinschreibung nicht beachtet, wenn es um Eigenschaftsnamen geht, besteht die C#-Konvention darin, den ersten Buchstaben von Eigenschaftsnamen groß zu schreiben.

  2. Verwenden Sie die HttpClientJsonExtensions.GetFromJsonAsync Methode, um JSON in C#-Objekte abzurufen und zu konvertieren. Ersetzen Sie den Aufruf GetStringAsync(String) in der ProcessRepositoriesAsync Methode durch die folgenden Zeilen:

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

    Der aktualisierte Code ersetzt GetStringAsync(String) durch HttpClientJsonExtensions.GetFromJsonAsync.

    Das erste Argument für die GetFromJsonAsync Methode ist ein await Ausdruck. await Ausdrücke können fast überall im Code angezeigt werden, obwohl Sie sie bis jetzt nur als Teil einer Zuordnungsanweisung gesehen haben. Der nächste Parameter ist optional und muss nicht angegeben werden, requestUri wenn er beim Erstellen des client Objekts bereits angegeben wurde. Sie haben das client Objekt nicht mit dem URI zum Senden der Anforderung bereitgestellt, sodass Sie den URI jetzt angegeben haben. Der letzte optionale Parameter, der CancellationToken im Codeausschnitt weggelassen wird.

    Die GetFromJsonAsync Methode ist generisch, was bedeutet, dass Sie Typargumente für die Art von Objekten angeben, die aus dem abgerufenen JSON-Text erstellt werden sollen. In diesem Beispiel wird eine Deserialisierung für ein List<Repository>anderes generisches Objekt (ein anderes generisches Objekt) ausgeführt System.Collections.Generic.List<T>. Die List<T> Klasse speichert eine Auflistung von Objekten. Das Typargument deklariert den Typ der objekte, die in der List<T>. Das Typargument ist Ihr Repository Datensatz, da der JSON-Text eine Auflistung von Repositoryobjekten darstellt.

  3. Fügen Sie Code hinzu, um den Namen der einzelnen Repositorys anzuzeigen. Ersetzen Sie die Zeilen, die gelesen werden:

    Console.Write(json);
    

    mit folgendem Code:

    foreach (var repo in repositories ?? Enumerable.Empty<Repository>())
        Console.WriteLine(repo.Name);
    
  4. Die folgenden using Richtlinien sollten am Anfang der Datei vorhanden sein:

    using System.Net.Http.Headers;
    using System.Net.Http.Json;
    
  5. Führen Sie die App aus.

    dotnet run
    

    Die Ausgabe ist eine Liste der Namen der Repositorys, die Teil von .NET Foundation sind.

Umgestalten des Codes

Die ProcessRepositoriesAsync Methode kann die asynchrone Arbeit ausführen und eine Sammlung der Repositorys zurückgeben. Ändern Sie diese Methode, um sie zurückzugeben Task<List<Repository>>, und verschieben Sie den Code, der in die Konsole in der Nähe des Aufrufers schreibt.

  1. Ändern Sie die Signatur, ProcessRepositoriesAsync um eine Aufgabe zurückzugeben, deren Ergebnis eine Liste von Repository Objekten ist:

    static async Task<List<Repository>> ProcessRepositoriesAsync(HttpClient client)
    
  2. Geben Sie die Repositorys nach der Verarbeitung der JSON-Antwort zurück:

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

    Der Compiler generiert das Task<T> Objekt für den Rückgabewert, da Sie diese Methode als asyncgekennzeichnet haben.

  3. Ändern Sie die Program.cs Datei, und ersetzen Sie den Aufruf ProcessRepositoriesAsync durch Folgendes, um die Ergebnisse zu erfassen, und schreiben Sie jeden Repositorynamen in die Konsole.

    var repositories = await ProcessRepositoriesAsync(client);
    
    foreach (var repo in repositories)
        Console.WriteLine(repo.Name);
    
  4. Führen Sie die App aus.

    Die Ausgabe ist identisch.

Deserialisieren weiterer Eigenschaften

In den folgenden Schritten erweitern wir den Code, um weitere Eigenschaften aus der JSON-Nutzlast zu verarbeiten, die von der GitHub-API zurückgegeben wird. Wahrscheinlich müssen Sie nicht jede Eigenschaft verarbeiten, aber das Hinzufügen einiger Eigenschaften veranschaulicht zusätzliche C#-Features.

  1. Ersetzen Sie den Inhalt der Repository Klasse durch die folgende record Definition. Stellen Sie sicher, dass Sie den System.Text.Json.Serialization Namespace importieren und das [JsonPropertyName] Attribut anwenden, um JSON-Felder explizit C#-Eigenschaften zuzuordnen.

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

    Die Und Uri Typen int verfügen über integrierte Funktionen zum Konvertieren in und aus der Zeichenfolgendarstellung. Für die Deserialisierung von JSON-Zeichenfolgenformaten an diese Zieltypen ist kein zusätzlicher Code erforderlich. Wenn das JSON-Paket Daten enthält, die nicht in einen Zieltyp konvertiert werden, löst die Serialisierungsaktion eine Ausnahme aus.

    JSON verwendet lowercase häufig oder snake_case für Eigenschaftsnamen. Felder wie html_url und pushed_at folgen nicht den C#-PascalCase-Benennungskonventionen. Indem [JsonPropertyName] verwendet wird, wird sichergestellt, dass diese JSON-Schlüssel ordnungsgemäß an ihre entsprechenden C#-Eigenschaften gebunden sind, auch wenn sich ihre Namen in der Groß- und Kleinschreibung unterscheiden oder Unterstriche enthalten. Dieser Ansatz garantiert vorhersehbare und stabile Deserialisierung, während PascalCase-Eigenschaftsnamen in C# zugelassen werden. Darüber hinaus ist GetFromJsonAsync die case-insensitive Methode beim Abgleichen von Eigenschaftsnamen, daher ist keine weitere Konvertierung erforderlich.

  2. Aktualisieren Sie die foreach Schleife in der datei Program.cs so, dass die Eigenschaftswerte angezeigt werden:

    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. Führen Sie die App aus.

    Die Liste enthält jetzt die zusätzlichen Eigenschaften.

Hinzufügen einer Datumseigenschaft

Das Datum des letzten Pushvorgangs wird in dieser Weise in der JSON-Antwort formatiert:

2016-02-08T21:27:00Z

Dieses Format gilt für koordinierte Weltzeit (UTC), sodass das Ergebnis der Deserialisierung ein DateTime Wert ist, dessen Kind Eigenschaft lautet Utc.

Zum Abrufen eines Datums und einer Uhrzeit, das in Ihrer Zeitzone dargestellt wird, müssen Sie eine benutzerdefinierte Konvertierungsmethode schreiben.

  1. Fügen Sie in Repository.cs eine Eigenschaft für die UTC-Darstellung des Datums und der Uhrzeit und einer readonly-Eigenschaft LastPush hinzu, die das in lokale Uhrzeit konvertierte Datum zurückgibt, sollte die Datei wie folgt aussehen:

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

    Die LastPush Eigenschaft wird mithilfe eines Ausdruckskörperelements für den get Accessor definiert. Es gibt keinen set Accessor. Das Weglassen des set Accessors ist eine Möglichkeit, eine schreibgeschützte Eigenschaft in C# zu definieren. (Ja, Sie können schreibgeschützte Eigenschaften in C# erstellen, aber deren Wert ist begrenzt.)

  2. Fügen Sie eine weitere Ausgabeausweisung in Program.cs hinzu: erneut:

    Console.WriteLine($"Last push: {repo.LastPush}");
    
  3. Die vollständige App sollte der folgenden Program.cs Datei ähneln:

    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. Führen Sie die App aus.

    Die Ausgabe enthält das Datum und die Uhrzeit des letzten Pushs an jedes Repository.

Nächste Schritte

In diesem Lernprogramm haben Sie eine App erstellt, die Webanforderungen sendet und die Ergebnisse analysiert. Ihre Version der App sollte nun mit dem fertigen Beispiel übereinstimmen.

Erfahren Sie mehr über das Konfigurieren der JSON-Serialisierung in how to serialize and deserialize (marshal and unmarshal) JSON in .NET.