Tutorial: Übermitteln von HTTP-Anforderungen in einer .NET-Konsolen-App mit C#
In diesem Tutorial erstellen Sie eine App, die HTTP-Anforderungen an einen REST-Dienst in GitHub übermittelt. Die App liest Informationen im JSON-Format und konvertiert den JSON-Code in C#-Objekte. Die Konvertierung von JSON-Code in C#-Objekte wird als Deserialisierung bezeichnet.
In diesem Tutorial lernen Sie Folgendes:
- Senden von HTTP-Anforderungen
- Deserialisieren von JSON-Antworten
- Konfigurieren der Deserialisierung mit Attributen
Wenn Sie lieber das vollständige Beispiel für dieses Tutorial befolgen möchten, können Sie es herunterladen. Anweisungen zum Herunterladen finden Sie unter Beispiele und Lernprogramme.
Voraussetzungen
- .NET SDK 6.0 oder höher
- Ein Code-Editor wie [Visual Studio Code, (ein plattformübergreifender Open-Source-Editor). Sie können die Beispiel-App unter Windows, Linux oder macOS oder auch in einem Docker-Container ausführen.
Erstellen der Client-App
Öffnen Sie eine Eingabeaufforderung, und erstellen Sie ein neues Verzeichnis für Ihre App. Legen Sie das Verzeichnis als aktuelles Verzeichnis fest.
Geben Sie den folgenden Befehl in ein Konsolenfenster ein:
dotnet new console --name WebAPIClient
Mit diesem Befehl werden die Startdateien für eine einfache „Hallo Welt“-App erstellt. Der Projektname lautet „WebAPIClient“.
Navigieren Sie zum Verzeichnis „WebAPIClient“, und führen Sie die App aus.
cd WebAPIClient
dotnet run
Mit
dotnet run
wird automatischdotnet restore
ausgeführt, um alle Abhängigkeiten wiederherzustellen, die von der App benötigt werden. Außerdem wird bei Bedarfdotnet build
ausgeführt. Sie sollten die Ausgabe"Hello, World!"
der App sehen. 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 Schirm der .NET Foundation zu erhalten. Der Endpunkt ist https://api.github.com/orgs/dotnet/repos. Zum Abrufen von Informationen wird eine HTTP GET-Anforderung gesendet. Browser verwenden ebenfalls HTTP GET-Anforderungen, daher können Sie diese URL auf der Adressleiste Ihres Browsers einfügen, um zu sehen, welche Informationen abgerufen und verarbeitet werden.
Verwenden Sie die HttpClient-Klasse, um HTTP-Anforderungen zu übermitteln. HttpClient unterstützt für die APIs mit langer Ausführungszeit nur asynchrone Methoden. Daher wird mit den folgenden Schritten eine asynchrone Methode erstellt und über die Main-Methode aufgerufen.
Öffnen Sie die Datei
Program.cs
in Ihrem Projektverzeichnis und ersetzen Sie ihren Inhalt durch Folgendes:await ProcessRepositoriesAsync(); static async Task ProcessRepositoriesAsync(HttpClient client) { }
Mit diesem Code wird Folgendes durchgeführt:
- Ersetzen der
Console.WriteLine
-Anweisung durch einen Aufruf vonProcessRepositoriesAsync
, der das Schlüsselwortawait
verwendet - Definiert eine leere
ProcessRepositoriesAsync
-Methode.
- Ersetzen der
Verwenden Sie in der
Program
-Klasse einen HttpClient, um Anforderungen und Antworten zu verarbeiten, indem Sie den Inhalt durch das folgende 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) { }
Mit diesem Code wird Folgendes durchgeführt:
- Einrichten der HTTP-Header für alle Anforderungen:
- Ein
Accept
-Header zum Akzeptieren von JSON-Antworten - Ein
User-Agent
-Header. Diese Header werden vom GitHub-Servercode überprüft und sind erforderlich, um Informationen aus GitHub abzurufen.
- Ein
- Einrichten der HTTP-Header für alle Anforderungen:
Rufen Sie in der
ProcessRepositoriesAsync
-Methode den GitHub-Endpunkt auf, der eine Liste aller Repositorys unter der Organisation der .NET Foundation zurückgibt:static async Task ProcessRepositoriesAsync(HttpClient client) { var json = await client.GetStringAsync( "https://api.github.com/orgs/dotnet/repos"); Console.Write(json); }
Mit diesem Code wird Folgendes durchgeführt:
- Wartet auf den Task, der vom Aufrufen der HttpClient.GetStringAsync(String)-Methode zurückgegeben wird. Diese Methode sendet eine HTTP GET-Anforderung an den angegebenen URI. Der Text der Antwort wird als String zurückgegeben, der nach Abschluss der Aufgabe verfügbar ist.
- Die Antwortzeichenfolge
json
wird in der Konsole ausgegeben.
Erstellen Sie die App, und führen Sie sie aus.
dotnet run
Es wird keine Buildwarnung ausgegeben, da
ProcessRepositoriesAsync
jetzt einenawait
-Operator enthält. Die Ausgabe ist eine lange Darstellung von JSON-Text.
Deserialisieren des JSON-Ergebnisses
Mit den folgenden Schritten wird die JSON-Antwort in C#-Objekte konvertiert. Sie verwenden die System.Text.Json.JsonSerializer-Klasse, um JSON-Code in Objekte zu deserialisieren.
Erstellen Sie eine Datei mit dem Namen Repository.cs, und fügen Sie den folgenden Code hinzu:
public record class Repository(string name);
Mit diesem Code definieren Sie eine Klasse, die das von der GitHub-API zurückgegebene JSON-Objekt darstellt. Sie verwenden diese Klasse, um eine Liste mit Repositorynamen anzuzeigen.
Der JSON-Code für ein Repositoryobjekt enthält Dutzende von Eigenschaften, aber nur die
name
-Eigenschaft wird deserialisiert. Das Serialisierungsmodul ignoriert automatisch alle JSON-Eigenschaften, für die keine Übereinstimmung in der Zielklasse vorliegt. Dieses Feature vereinfacht die Erstellung von Typen, die nur mit einem Teilsatz der Felder in einem großen JSON-Paket funktionieren.Laut C#-Konvention wird der erste Buchstabe von Eigenschaftennamen groß geschrieben, aber die
name
-Eigenschaft beginnt hier mit einem Kleinbuchstaben, da dies genau dem JSON-Code entspricht. Später erfahren Sie, wie Sie C#-Eigenschaftennamen verwenden, die nicht mit den JSON-Eigenschaftennamen übereinstimmen.Verwenden Sie das Serialisierungsmodul, um JSON-Code in C#-Objekte zu konvertieren. Ersetzen Sie den Aufruf von GetStringAsync(String) in der
ProcessRepositoriesAsync
-Methode durch die folgenden Zeilen:await using Stream stream = await client.GetStreamAsync("https://api.github.com/orgs/dotnet/repos"); var repositories = await JsonSerializer.DeserializeAsync<List<Repository>>(stream);
Im aktualisierten Code wird GetStringAsync(String) durch GetStreamAsync(String) ersetzt. Die Methode des Serialisierungsmoduls nutzt anstelle einer Zeichenfolge einen Stream als Quelle.
Das erste Argument für JsonSerializer.DeserializeAsync<TValue>(Stream, JsonSerializerOptions, CancellationToken) ist ein
await
-Ausdruck.await
-Ausdrücke können fast überall in Ihrem Code stehen, obwohl sie bisher nur als Teil einer Zuweisungsanweisung verwendet wurden. Die anderen beiden ParameterJsonSerializerOptions
undCancellationToken
sind optional und werden im Codeausschnitt ausgelassen.Die
DeserializeAsync
-Methode ist generisch. Das bedeutet, dass Sie Typargumente für die Objekttypen angeben müssen, die aus dem JSON-Text erstellt werden sollen. In diesem Beispiel deserialisieren Sie in einList<Repository>
. Dabei handelt es sich um ein weiteres generisches Objekt, System.Collections.Generic.List<T>. DieList<T>
-Klasse speichert eine Sammlung von Objekten. Das Typargument deklariert den Typ der inList<T>
gespeicherten Objekte. Das Typargument ist IhrRepository
-Datensatz, da der JSON-Text eine Auflistung von Repositoryobjekten darstellt.Fügen Sie Code hinzu, um die Namen der einzelnen Repositorys anzuzeigen. Ersetzen Sie diese Zeilen:
Console.Write(json);
durch den folgenden Code:
foreach (var repo in repositories ?? Enumerable.Empty<Repository>()) Console.Write(repo.name);
Die folgenden
using
-Anweisungen sollten am Anfang der Datei vorhanden sein:using System.Net.Http.Headers; using System.Text.Json;
Führen Sie die App aus.
dotnet run
Die Ausgabe ist eine Liste der Namen der Repositorys, die zur .NET Foundation gehören.
Konfigurieren der Deserialisierung
Ersetzen Sie in Repository.cs den Inhalt der Datei durch die folgende C#.
using System.Text.Json.Serialization; public record class Repository( [property: JsonPropertyName("name")] string Name);
Mit diesem Code wird Folgendes durchgeführt:
- Ändert den Namen der
name
-Eigenschaft inName
. - Fügt das JsonPropertyNameAttribute hinzu, um anzugeben, wie diese Eigenschaft im JSON-Code angezeigt wird.
- Ändert den Namen der
Aktualisieren Sie in Program.cs den Code so, dass er die neue Groß-/Kleinschreibung der
Name
-Eigenschaft verwendet:foreach (var repo in repositories) Console.Write(repo.Name);
Führen Sie die App aus.
Die Ausgabe ist identisch.
Gestalten Sie den Code um.
Die ProcessRepositoriesAsync
-Methode kann die asynchrone Arbeit erledigen und eine Auflistung der Repositorys zurückgeben. Ändern Sie diese Methode, um Task<List<Repository>>
zurückzugeben, und verschieben Sie den Code, der in die Konsole schreibt, in die Nähe des Aufrufers.
Ändern Sie die Signatur von
ProcessRepositoriesAsync
, um einen Task zurückzugeben, dessen Ergebnis eine Liste mitRepository
-Objekten ist:static async Task<List<Repository>> ProcessRepositoriesAsync(HttpClient client)
Geben Sie die Repositorys zurück, nachdem die JSON-Antwort verarbeitet wurde:
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();
Der Compiler generiert das
Task<T>
-Objekt für den Rückgabewert, da Sie diese Methode alsasync
markiert haben.Ändern Sie die Datei Program.cs, und ersetzen Sie den Aufruf von
ProcessRepositoriesAsync
durch Folgendes, um die Ergebnisse zu erfassen und die einzelnen Repositorynamen in die Konsole zu schreiben.var repositories = await ProcessRepositoriesAsync(client); foreach (var repo in repositories) Console.Write(repo.Name);
Führen Sie die App aus.
Die Ausgabe ist identisch.
Deserialisieren weiterer Eigenschaften
In den folgenden Schritten fügen Sie Code hinzu, um weitere Eigenschaften im empfangenen JSON-Paket zu verarbeiten. Wahrscheinlich möchten Sie nicht jede Eigenschaft verarbeiten, aber das Hinzufügen einiger weiterer veranschaulicht andere Features von C#.
Ersetzen Sie den Inhalt der Klasse
Repository
durch die folgenderecord
-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);
Die Typen Uri und
int
verfügen über integrierte Funktionen zum Konvertieren in und aus Zeichenfolgendarstellungen. Es ist kein zusätzlicher Code erforderlich, um das JSON-Zeichenfolgenformat in diese Zieltypen zu deserialisieren. Wenn das JSON-Paket Daten enthält, die nicht in einen Zieltyp konvertiert werden können, löst die Serialisierungsaktion eine Ausnahme aus.Aktualisieren Sie die
foreach
-Schleife in der Datei Program.cs, um die Eigenschaftswerte anzuzeigen: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(); }
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 der JSON-Antwort wie folgt formatiert:
2016-02-08T21:27:00Z
Dieses Format entspricht der koordinierten Weltzeit (UTC), sodass das Ergebnis der Deserialisierung ein DateTime-Wert ist, dessen Kind-Eigenschaft Utc lautet.
Wenn Sie ein Datum in Ihrer Zeitzone bevorzugen, müssen Sie eine benutzerdefinierte Methode für die Konvertierung schreiben.
Fügen Sie in Repository.cs eine Eigenschaft für die UTC-Darstellung des Datums und der Uhrzeit sowie eine
LastPush
Eigenschaft hinzu, die das in die Ortszeit umgerechnete Datum zurückgibt. Die Datei sollte wie folgt aussehen: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(); }
Die
LastPush
-Eigenschaft wird mit einem Ausdruckskörpermember für dieget
-Zugriffsmethode definiert. Es gibt keineset
-Zugriffsmethode. Das Auslassen derset
-Zugriffsmethode ist eine Möglichkeit, eine schreibgeschützte Eigenschaft in C# zu definieren. (Ja, Sie können lesegeschützte Eigenschaften in C# erstellen, aber ihr Wert ist begrenzt.)Fügen Sie in Program.cs eine weitere Ausgabeanweisung hinzu:
Console.WriteLine($"Last push: {repo.LastPush}");
Die vollständige App sollte der folgenden Program.cs-Datei ähneln:
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(); }
Führen Sie die App aus.
Die Ausgabe enthält das Datum und die Uhrzeit des jeweils letzten Pushs an jedes Repository.
Nächste Schritte
In diesem Tutorial haben Sie eine App erstellt, die Webanforderungen ausführt und die Ergebnisse analysiert. Ihre Version der App sollte nun dem vollständigen Beispiel entsprechen.
Weitere Informationen zum Konfigurieren der JSON-Serialisierung finden Sie unter Serialisieren und Deserialisieren (Marshallen und Rückgängigmachen des Marshallens) von JSON-Daten in .NET.