Ausführen von HTTP-Anforderungen mit der HttpClient-Klasse

In diesem Artikel erfahren Sie, wie Sie HTTP-Anforderungen erstellen und Antworten mit der HttpClient-Klasse verarbeiten.

Wichtig

Alle HTTP-Beispielanforderungen verwenden eine der folgenden Ziel-URLs:

HTTP-Endpunkte geben häufig JSON-Daten (JavaScript Object Notation) zurück, aber nicht immer. Der Einfachheit halber bietet das optionale NuGet-Paket System.Net.Http.Json mehrere Erweiterungsmethoden für HttpClient und HttpContent, die eine automatische Serialisierung und Deserialisierung mit System.Text.Json durchführen. Die folgenden Beispiele machen auf Orte aufmerksam, an denen diese Erweiterungen verfügbar sind.

Tipp

Der gesamte Quellcode aus diesem Artikel ist im Repository GitHub: .NET-Dokumentation verfügbar.

Erstellen Sie einen HttpClient.

Die meisten der folgenden Beispiele verwenden dieselbe HttpClient-Instanz und müssen daher nur einmal konfiguriert werden. Verwenden Sie den Konstruktor der Klasse HttpClient, um einen HttpClient zu erstellen. Weitere Informationen finden Sie unter Richtlinien für die Verwendung von HttpClient.

// HttpClient lifecycle management best practices:
// https://learn.microsoft.com/dotnet/fundamentals/networking/http/httpclient-guidelines#recommended-use
private static HttpClient sharedClient = new()
{
    BaseAddress = new Uri("https://jsonplaceholder.typicode.com"),
};

Der vorangehende Code:

  • Instanziiert eine neue HttpClient-Instanz als Variable des Typs static. Gemäß den Richtlinien wird dringend empfohlen, HttpClient-Instanzen im Lebenszyklus der Anwendung wiederzuverwenden.
  • Legt den Wert von HttpClient.BaseAddress auf "https://jsonplaceholder.typicode.com" fest.

Diese HttpClient-Instanz verwendet bei nachfolgenden Anforderungen immer die Basisadresse. Wenn Sie eine andere Konfiguration anwenden möchten, ziehen Sie Folgendes in Betracht:

Tipp

Alternativ können Sie HttpClient-Instanzen mithilfe eines Factorymusteransatzes erstellen, der es Ihnen ermöglicht, eine beliebige Anzahl von Clients zu konfigurieren und diese als Dienst zur Abhängigkeitsinjektion zu verwenden. Weitere Informationen finden Sie unter HTTP-Clientfactory mit .NET.

Senden einer HTTP-Anforderung

Um eine HTTP-Anforderung auszuführen, rufen Sie eine beliebige der folgenden APIs auf:

HTTP-Methode API
GET HttpClient.GetAsync
GET HttpClient.GetByteArrayAsync
GET HttpClient.GetStreamAsync
GET HttpClient.GetStringAsync
POST HttpClient.PostAsync
PUT HttpClient.PutAsync
PATCH HttpClient.PatchAsync
DELETE HttpClient.DeleteAsync
USER SPECIFIED HttpClient.SendAsync

Eine USER SPECIFIED-Anforderung weist darauf hin, dass die Methode SendAsync jede gültige HttpMethod akzeptiert.

Warnung

Das Ausführen von HTTP-Anforderungen wird als Netzwerk-E/A-gebundene Arbeit betrachtet. Es gibt zwar eine synchrone HttpClient.Send-Methode, aber es wird empfohlen, stattdessen die asynchronen APIs zu verwenden – es sei denn, Sie haben gute Gründe, dies nicht zu tun.

HTTP-Inhalt

Der Typ HttpContent wird verwendet, um HTTP-Entitätstext und die zugehörigen Inhaltsheader darzustellen. Für HTTP-Methoden (oder Anforderungsmethoden), die einen Text benötigen (POST, PUT und PATCH), verwenden Sie die Klasse HttpContent, um den Text der Anforderung anzugeben. Die meisten Beispiele zeigen, wie Sie die StringContent-Unterklasse mit JSON-Nutzdaten vorbereiten, aber es gibt weitere Unterklassen für verschiedene Inhaltstypen (MIME).

  • ByteArrayContent: Stellt HTTP-Inhalt auf der Grundlage eines Bytearrays bereit.
  • FormUrlEncodedContent: Stellt HTTP-Inhalt für Namens-/Werttupel bereit, die mit dem MIME-Typ "application/x-www-form-urlencoded" codiert sind.
  • JsonContent: Stellt HTTP-Inhalt auf Grundlage von JSON bereit.
  • MultipartContent: Stellt eine Auflistung von HttpContent-Objekten bereit, die mithilfe der MIME-Typspezifikation "multipart/*" serialisiert werden.
  • MultipartFormDataContent: Stellt einen Container für Inhalt bereit, der mithilfe des MIME-Typs "multipart/form-data" codiert wurde.
  • ReadOnlyMemoryContent: Stellt HTTP-Inhalt auf der Grundlage von ReadOnlyMemory<T> bereit.
  • StreamContent: Stellt HTTP-Inhalt auf der Grundlage eines Streams bereit.
  • StringContent: Stellt HTTP-Inhalt auf der Grundlage einer Zeichenfolge bereit.

Die Klasse HttpContent wird auch zur Darstellung des Antworttexts von HttpResponseMessage verwendet, auf den über die Eigenschaft HttpResponseMessage.Content zugegriffen werden kann.

HTTP Get

Eine GET-Anforderung sollte keinen Text senden und wird (wie der Name der Methode vermuten lässt) verwendet, um Daten aus einer Ressource abzurufen (oder zu empfangen). Um eine HTTP-GET-Anforderung mit einem HttpClient und einem URI auszuführen, verwenden Sie die Methode HttpClient.GetAsync:

static async Task GetAsync(HttpClient httpClient)
{
    using HttpResponseMessage response = await httpClient.GetAsync("todos/3");
    
    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();
    
    var jsonResponse = await response.Content.ReadAsStringAsync();
    Console.WriteLine($"{jsonResponse}\n");

    // Expected output:
    //   GET https://jsonplaceholder.typicode.com/todos/3 HTTP/1.1
    //   {
    //     "userId": 1,
    //     "id": 3,
    //     "title": "fugiat veniam minus",
    //     "completed": false
    //   }
}

Der vorangehende Code:

  • Sendet eine GET-Anforderung an "https://jsonplaceholder.typicode.com/todos/3".
  • Stellt sicher, dass die Antwort erfolgreich ist.
  • Gibt die Anforderungsdetails in der Konsole aus.
  • Liest den Antworttext als Zeichenfolge.
  • Gibt den JSON-Antworttext in der Konsole aus.

Bei WriteRequestToConsole handelt es sich um eine benutzerdefinierte Erweiterungsmethode, die nicht Teil des Frameworks ist. Wenn Sie jedoch wissen möchten, wie sie implementiert wird, sehen Sie sich den folgenden C#-Code an:

static class HttpResponseMessageExtensions
{
    internal static void WriteRequestToConsole(this HttpResponseMessage response)
    {
        if (response is null)
        {
            return;
        }

        var request = response.RequestMessage;
        Console.Write($"{request?.Method} ");
        Console.Write($"{request?.RequestUri} ");
        Console.WriteLine($"HTTP/{request?.Version}");        
    }
}

Diese Funktionalität wird verwendet, um die Anforderungsdetails in folgender Form in die Konsole einzugeben:

<HTTP Request Method> <Request URI> <HTTP/Version>

Als Beispiel gibt die GET-Anforderung für https://jsonplaceholder.typicode.com/todos/3 die folgende Meldung aus:

GET https://jsonplaceholder.typicode.com/todos/3 HTTP/1.1

HTTP GET aus JSON

Der Endpunkt https://jsonplaceholder.typicode.com/todos gibt ein JSON-Array mit Todo-Objekten zurück. Ihre JSON-Struktur sieht ungefähr so aus:

[
  {
    "userId": 1,
    "id": 1,
    "title": "example title",
    "completed": false
  },
  {
    "userId": 1,
    "id": 2,
    "title": "another example title",
    "completed": true
  },
]

Das C#-Objekt Todo ist wie folgt definiert:

public record class Todo(
    int? UserId = null,
    int? Id = null,
    string? Title = null,
    bool? Completed = null);

Es handelt sich um einen record class-Typ mit den optionalen Eigenschaften Id, Title, Completed und UserId. Weitere Informationen zum Typ record finden Sie unter Einführung in Datensatztypen in C#. Um GET-Anforderungen automatisch in stark typisierte C#-Objekte zu deserialisieren, verwenden Sie die Erweiterungsmethode GetFromJsonAsync, die im NuGet-Paket System.Net.Http.Json enthalten ist.

static async Task GetFromJsonAsync(HttpClient httpClient)
{
    var todos = await httpClient.GetFromJsonAsync<List<Todo>>(
        "todos?userId=1&completed=false");

    Console.WriteLine("GET https://jsonplaceholder.typicode.com/todos?userId=1&completed=false HTTP/1.1");
    todos?.ForEach(Console.WriteLine);
    Console.WriteLine();

    // Expected output:
    //   GET https://jsonplaceholder.typicode.com/todos?userId=1&completed=false HTTP/1.1
    //   Todo { UserId = 1, Id = 1, Title = delectus aut autem, Completed = False }
    //   Todo { UserId = 1, Id = 2, Title = quis ut nam facilis et officia qui, Completed = False }
    //   Todo { UserId = 1, Id = 3, Title = fugiat veniam minus, Completed = False }
    //   Todo { UserId = 1, Id = 5, Title = laboriosam mollitia et enim quasi adipisci quia provident illum, Completed = False }
    //   Todo { UserId = 1, Id = 6, Title = qui ullam ratione quibusdam voluptatem quia omnis, Completed = False }
    //   Todo { UserId = 1, Id = 7, Title = illo expedita consequatur quia in, Completed = False }
    //   Todo { UserId = 1, Id = 9, Title = molestiae perspiciatis ipsa, Completed = False }
    //   Todo { UserId = 1, Id = 13, Title = et doloremque nulla, Completed = False }
    //   Todo { UserId = 1, Id = 18, Title = dolorum est consequatur ea mollitia in culpa, Completed = False }
}

Für den Code oben gilt:

  • Es wird eine GET-Anforderung an "https://jsonplaceholder.typicode.com/todos?userId=1&completed=false" gesendet.
    • Die Abfragezeichenfolge repräsentiert die Filterkriterien für die Anforderung.
  • Die Antwort wird automatisch in eine List<Todo> deserialisiert, wenn sie erfolgreich ist.
  • Die Details der Anforderung werden gemeinsam mit jedem Todo-Objekt in der Konsole ausgegeben.

HTTP POST

Eine POST-Anforderung sendet Daten zur Verarbeitung an den Server. Der Content-Type-Header der Anforderung gibt an, welcher MIME-Typ im Text gesendet wird. Um eine HTTP-Anforderung POST mit einem HttpClient und einem Uriauszuführen, verwenden Sie die HttpClient.PostAsync-Methode:

static async Task PostAsync(HttpClient httpClient)
{
    using StringContent jsonContent = new(
        JsonSerializer.Serialize(new
        {
            userId = 77,
            id = 1,
            title = "write code sample",
            completed = false
        }),
        Encoding.UTF8,
        "application/json");

    using HttpResponseMessage response = await httpClient.PostAsync(
        "todos",
        jsonContent);

    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();
    
    var jsonResponse = await response.Content.ReadAsStringAsync();
    Console.WriteLine($"{jsonResponse}\n");

    // Expected output:
    //   POST https://jsonplaceholder.typicode.com/todos HTTP/1.1
    //   {
    //     "userId": 77,
    //     "id": 201,
    //     "title": "write code sample",
    //     "completed": false
    //   }
}

Der vorangehende Code:

  • Bereitet eine StringContent-Instanz mit dem JSON-Text der Anforderung vor (MIME-Typ "application/json").
  • Sendet eine POST-Anforderung an "https://jsonplaceholder.typicode.com/todos".
  • Stellt sicher, dass die Antwort erfolgreich ist, und gibt die Anforderungsdetails in der Konsole aus.
  • Gibt den Antworttext als Zeichenfolge in der Konsole aus.

HTTP POST aus JSON

Um POST-Anforderungsargumente automatisch zu serialisieren und Antworten in stark typisierte C#-Objekte zu deserialisieren, verwenden Sie die Erweiterungsmethode PostAsJsonAsync, die im NuGet-Paket System.Net.Http.Json enthalten ist.

static async Task PostAsJsonAsync(HttpClient httpClient)
{
    using HttpResponseMessage response = await httpClient.PostAsJsonAsync(
        "todos", 
        new Todo(UserId: 9, Id: 99, Title: "Show extensions", Completed: false));

    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();

    var todo = await response.Content.ReadFromJsonAsync<Todo>();
    Console.WriteLine($"{todo}\n");

    // Expected output:
    //   POST https://jsonplaceholder.typicode.com/todos HTTP/1.1
    //   Todo { UserId = 9, Id = 201, Title = Show extensions, Completed = False }
}

Der vorangehende Code:

  • Serialisiert die Todo-Instanz als JSON und sendet eine POST-Anforderung an "https://jsonplaceholder.typicode.com/todos".
  • Stellt sicher, dass die Antwort erfolgreich ist, und gibt die Anforderungsdetails in der Konsole aus.
  • Deserialisiert den Antworttext in eine Todo-Instanz und gibt das Todo-Element in der Konsole aus.

HTTP PUT

Die PUT-Anforderungsmethode ersetzt entweder eine vorhandene Ressource oder erstellt anhand der Nutzdaten im Anforderungstext eine neue Ressource. Um eine HTTP-PUT-Anforderung mit einem HttpClient und einem URI auszuführen, verwenden Sie die Methode HttpClient.PutAsync:

static async Task PutAsync(HttpClient httpClient)
{
    using StringContent jsonContent = new(
        JsonSerializer.Serialize(new 
        {
            userId = 1,
            id = 1,
            title = "foo bar",
            completed = false
        }),
        Encoding.UTF8,
        "application/json");

    using HttpResponseMessage response = await httpClient.PutAsync(
        "todos/1",
        jsonContent);

    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();
    
    var jsonResponse = await response.Content.ReadAsStringAsync();
    Console.WriteLine($"{jsonResponse}\n");

    // Expected output:
    //   PUT https://jsonplaceholder.typicode.com/todos/1 HTTP/1.1
    //   {
    //     "userId": 1,
    //     "id": 1,
    //     "title": "foo bar",
    //     "completed": false
    //   }
}

Der vorangehende Code:

  • Bereitet eine StringContent-Instanz mit dem JSON-Text der Anforderung vor (MIME-Typ "application/json").
  • Sendet eine PUT-Anforderung an "https://jsonplaceholder.typicode.com/todos/1".
  • Stellt sicher, dass die Antwort erfolgreich ist, und gibt die Anforderungsdetails und den JSON-Antworttext in der Konsole aus.

HTTP PUT als JSON

Um PUT-Anforderungsargumente automatisch zu serialisieren und Antworten in stark typisierte C#-Objekte zu deserialisieren, verwenden Sie die Erweiterungsmethode PutAsJsonAsync, die im NuGet-Paket System.Net.Http.Json enthalten ist.

static async Task PutAsJsonAsync(HttpClient httpClient)
{
    using HttpResponseMessage response = await httpClient.PutAsJsonAsync(
        "todos/5",
        new Todo(Title: "partially update todo", Completed: true));

    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();

    var todo = await response.Content.ReadFromJsonAsync<Todo>();
    Console.WriteLine($"{todo}\n");

    // Expected output:
    //   PUT https://jsonplaceholder.typicode.com/todos/5 HTTP/1.1
    //   Todo { UserId = , Id = 5, Title = partially update todo, Completed = True }
}

Der vorangehende Code:

  • Serialisiert die Todo-Instanz als JSON und sendet eine PUT-Anforderung an "https://jsonplaceholder.typicode.com/todos/5".
  • Stellt sicher, dass die Antwort erfolgreich ist, und gibt die Anforderungsdetails in der Konsole aus.
  • Deserialisiert den Antworttext in eine Todo-Instanz und gibt das Todo-Element in der Konsole aus.

HTTP PATCH

Die PATCH-Anforderung bewirkt eine teilweise Aktualisierung einer vorhandenen Ressource. Es wird weder eine neue Ressource erstellt, noch soll eine vorhandene Ressource ersetzt werden. Stattdessen wird eine Ressource nur teilweise aktualisiert. Um eine HTTP-PATCH-Anforderung mit einem HttpClient und einem URI auszuführen, verwenden Sie die Methode HttpClient.PatchAsync:

static async Task PatchAsync(HttpClient httpClient)
{
    using StringContent jsonContent = new(
        JsonSerializer.Serialize(new
        {
            completed = true
        }),
        Encoding.UTF8,
        "application/json");

    using HttpResponseMessage response = await httpClient.PatchAsync(
        "todos/1",
        jsonContent);

    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();

    var jsonResponse = await response.Content.ReadAsStringAsync();
    Console.WriteLine($"{jsonResponse}\n");

    // Expected output
    //   PATCH https://jsonplaceholder.typicode.com/todos/1 HTTP/1.1
    //   {
    //     "userId": 1,
    //     "id": 1,
    //     "title": "delectus aut autem",
    //     "completed": true
    //   }
}

Der vorangehende Code:

  • Bereitet eine StringContent-Instanz mit dem JSON-Text der Anforderung vor (MIME-Typ "application/json").
  • Sendet eine PATCH-Anforderung an "https://jsonplaceholder.typicode.com/todos/1".
  • Stellt sicher, dass die Antwort erfolgreich ist, und gibt die Anforderungsdetails und den JSON-Antworttext in der Konsole aus.

Es gibt keine Erweiterungsmethoden für PATCH-Anforderungen im NuGet-Paket System.Net.Http.Json.

HTTP DELETE

Eine DELETE-Anforderung löscht eine vorhandene Ressource. Eine DELETE-Anforderung ist idempotent, aber nicht safe, d. h., mehrere DELETE-Anforderungen an dieselbe Ressource führen zum gleichen Ergebnis, aber die Anforderung beeinflusst den Zustand der Ressource. Um eine HTTP-DELETE-Anforderung mit einem HttpClient und einem URI auszuführen, verwenden Sie die Methode HttpClient.DeleteAsync:

static async Task DeleteAsync(HttpClient httpClient)
{
    using HttpResponseMessage response = await httpClient.DeleteAsync("todos/1");
    
    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();

    var jsonResponse = await response.Content.ReadAsStringAsync();
    Console.WriteLine($"{jsonResponse}\n");

    // Expected output
    //   DELETE https://jsonplaceholder.typicode.com/todos/1 HTTP/1.1
    //   {}
}

Der vorangehende Code:

  • Sendet eine DELETE-Anforderung an "https://jsonplaceholder.typicode.com/todos/1".
  • Stellt sicher, dass die Antwort erfolgreich ist, und gibt die Anforderungsdetails in der Konsole aus.

Tipp

Die Antwort auf eine DELETE-Anforderung kann (genau wie eine PUT-Anforderung) einen Text enthalten oder auch nicht.

HTTP HEAD

Die HEAD-Anforderung ähnelt einer GET-Anforderung. Anstatt die Ressource zurückzugeben, werden nur die mit der Ressource verbundenen Header zurückgegeben. Eine Antwort auf eine HEAD-Anforderung gibt keinen Text zurück. Um eine HTTP-HEAD-Anforderung mit einem HttpClient und einem URI auszuführen, verwenden Sie die Methode HttpClient.SendAsync und legen dabei HttpMethod auf HttpMethod.Head fest:

static async Task HeadAsync(HttpClient httpClient)
{
    using HttpRequestMessage request = new(
        HttpMethod.Head, 
        "https://www.example.com");

    using HttpResponseMessage response = await httpClient.SendAsync(request);

    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();

    foreach (var header in response.Headers)
    {
        Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
    }
    Console.WriteLine();

    // Expected output:
    //   HEAD https://www.example.com/ HTTP/1.1
    //   Accept-Ranges: bytes
    //   Age: 550374
    //   Cache-Control: max-age=604800
    //   Date: Wed, 10 Aug 2022 17:24:55 GMT
    //   ETag: "3147526947"
    //   Server: ECS, (cha / 80E2)
    //   X-Cache: HIT
}

Der vorangehende Code:

  • Sendet eine HEAD-Anforderung an "https://www.example.com/".
  • Stellt sicher, dass die Antwort erfolgreich ist, und gibt die Anforderungsdetails in der Konsole aus.
  • Durchläuft alle Antwortheader, die jeweils in der Konsole ausgegeben werden.

HTTP OPTIONS

Mithilfe der OPTIONS-Anforderung wird festgestellt, welche HTTP-Methoden ein Server oder Endpunkt unterstützt. Um eine HTTP-OPTIONS-Anforderung mit einem HttpClient und einem URI auszuführen, verwenden Sie die Methode HttpClient.SendAsync und legen dabei HttpMethod auf HttpMethod.Options fest:

static async Task OptionsAsync(HttpClient httpClient)
{
    using HttpRequestMessage request = new(
        HttpMethod.Options, 
        "https://www.example.com");

    using HttpResponseMessage response = await httpClient.SendAsync(request);

    response.EnsureSuccessStatusCode()
        .WriteRequestToConsole();

    foreach (var header in response.Content.Headers)
    {
        Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
    }
    Console.WriteLine();

    // Expected output
    //   OPTIONS https://www.example.com/ HTTP/1.1
    //   Allow: OPTIONS, GET, HEAD, POST
    //   Content-Type: text/html; charset=utf-8
    //   Expires: Wed, 17 Aug 2022 17:28:42 GMT
    //   Content-Length: 0
}

Der vorangehende Code:

  • Sendet eine OPTIONS-HTTP-Anforderung an "https://www.example.com/".
  • Stellt sicher, dass die Antwort erfolgreich ist, und gibt die Anforderungsdetails in der Konsole aus.
  • Durchläuft alle Antwortinhaltsheader, die jeweils in der Konsole ausgegeben werden.

HTTP TRACE

Die TRACE-Anforderung kann für das Debuggen nützlich sein, da sie ein Loopback der Anforderungsnachricht auf Anwendungsebene bietet. Um eine HTTP-TRACE-Anforderung auszuführen, erstellen Sie mit HttpMethod.Trace eine HttpRequestMessage:

using HttpRequestMessage request = new(
    HttpMethod.Trace, 
    "{ValidRequestUri}");

Achtung

Die HTTP-Methode TRACE wird nicht von allen HTTP-Servern unterstützt. Bei unbedachter Verwendung kann sie ein Sicherheitsrisiko darstellen. Weitere Informationen finden Sie unter Open Web Application Security Project (OWASP): Cross Site Tracing.

Verarbeiten einer HTTP-Antwort

Wann immer Sie eine HTTP-Antwort verarbeiten, interagieren Sie mit dem Typ HttpResponseMessage. Zur Bewertung der Gültigkeit einer Antwort werden verschiedene Member herangezogen. Der HTTP-Statuscode ist über die Eigenschaft HttpResponseMessage.StatusCode verfügbar. Angenommen, Sie haben unter Angabe einer Clientinstanz eine Anforderung gesendet:

using HttpResponseMessage response = await httpClient.SendAsync(request);

Um sicherzustellen, dass response den Wert OK (HTTP-Statuscode 200) aufweist, können Sie eine Bewertung wie im folgenden Beispiel durchführen:

if (response is { StatusCode: HttpStatusCode.OK })
{
    // Omitted for brevity...
}

Es gibt zusätzliche HTTP-Statuscodes, die eine erfolgreiche Antwort repräsentieren, z. B. CREATED (HTTP-Statuscode 201), ACCEPTED (HTTP-Statuscode 202), NO CONTENT (HTTP-Statuscode 204) und RESET CONTENT (HTTP-Statuscode 205). Sie können auch die Eigenschaft HttpResponseMessage.IsSuccessStatusCode verwenden, um diese Codes auszuwerten. Auf diese Weise wird sichergestellt, dass der Antwortstatuscode im Bereich 200–299 liegt:

if (response.IsSuccessStatusCode)
{
    // Omitted for brevity...
}

Wenn das Framework eine HttpRequestException auslösen soll, können Sie die Methode HttpResponseMessage.EnsureSuccessStatusCode() aufrufen:

response.EnsureSuccessStatusCode();

Dieser Code löst eine HttpRequestException aus, wenn der Antwortstatuscode nicht im Bereich 200–299 liegt.

HTTP-Antworten mit gültigem Inhalt

Bei einer gültigen Antwort können Sie mit der Eigenschaft Content auf den Antworttext zugreifen. Der Text steht als HttpContent-Instanz zur Verfügung, die Sie nutzen können, um auf den Text als Stream, Bytearray oder Zeichenfolge zuzugreifen:

await using Stream responseStream =
    await response.Content.ReadAsStreamAsync();

Im vorangehenden Code kann responseStream zum Lesen des Antworttexts verwendet werden.

byte[] responseByteArray = await response.Content.ReadAsByteArrayAsync();

Im vorangehenden Code kann responseByteArray zum Lesen des Antworttexts verwendet werden.

string responseString = await response.Content.ReadAsStringAsync();

Im vorangehenden Code kann responseString zum Lesen des Antworttexts verwendet werden.

Wenn Sie wissen, dass ein HTTP-Endpunkt JSON zurückgibt, können Sie den Antworttext mithilfe des NuGet-Pakets System.Net.Http.Json in ein beliebiges gültiges C#-Objekt deserialisieren:

T? result = await response.Content.ReadFromJsonAsync<T>();

Im vorangehenden Code entspricht result dem als Typ T deserialisierten Antworttext.

HTTP-Fehlerbehandlung

Wenn eine HTTP-Anforderung fehlschlägt, wird HttpRequestException ausgelöst. Das Abfangen dieser Ausnahme allein reicht möglicherweise nicht aus, da es weitere potenzielle Ausnahmen gibt, die Sie möglicherweise behandeln müssen. Der aufrufende Code könnte beispielsweise ein Abbruchtoken verwenden, das vor Abschluss der Anforderung storniert wurde. In diesem Szenario würden Sie TaskCanceledException abfangen:

using var cts = new CancellationTokenSource();
try
{
    // Assuming:
    //   httpClient.Timeout = TimeSpan.FromSeconds(10)

    using var response = await httpClient.GetAsync(
        "http://localhost:5001/sleepFor?seconds=100", cts.Token);
}
catch (OperationCanceledException ex) when (cts.IsCancellationRequested)
{
    // When the token has been canceled, it is not a timeout.
    Console.WriteLine($"Canceled: {ex.Message}");
}

Ebenso wird bei einer HTTP-Anforderung die gleiche Ausnahme ausgelöst, wenn der Server bis zum Überschreiten von HttpClient.Timeout nicht antwortet. In diesem Szenario können Sie jedoch das Auftreten der Zeitüberschreitung erkennen, indem Sie beim Abfangen von TaskCanceledExceptionException.InnerException auswerten:

try
{
    // Assuming:
    //   httpClient.Timeout = TimeSpan.FromSeconds(10)

    using var response = await httpClient.GetAsync(
        "http://localhost:5001/sleepFor?seconds=100");
}
catch (OperationCanceledException ex) when (ex.InnerException is TimeoutException tex)
{
    Console.WriteLine($"Timed out: {ex.Message}, {tex.Message}");
}

Wenn es sich im vorangehenden Code bei der inneren Ausnahme um TimeoutException handelt, ist eine Zeitüberschreitung aufgetreten, und die Anforderung wurde nicht durch das Abbruchtoken storniert.

Um den HTTP-Statuscode beim Abfangen von HttpRequestException auszuwerten, können Sie die Eigenschaft HttpRequestException.StatusCode auswerten:

try
{
    // Assuming:
    //   httpClient.Timeout = TimeSpan.FromSeconds(10)

    using var response = await httpClient.GetAsync(
        "http://localhost:5001/doesNotExist");

    response.EnsureSuccessStatusCode();
}
catch (HttpRequestException ex) when (ex is { StatusCode: HttpStatusCode.NotFound })
{
    // Handle 404
    Console.WriteLine($"Not found: {ex.Message}");
}

Im vorangehenden Code wird die Methode EnsureSuccessStatusCode() aufgerufen, um eine Ausnahme auszulösen, wenn die Antwort nicht erfolgreich ist. Anschließend wird die Eigenschaft HttpRequestException.StatusCode ausgewertet, um festzustellen, ob es sich um eine 404-Antwort handelt (HTTP-Statuscode 404). Es gibt verschiedene Hilfsmethoden in HttpClient, die implizit EnsureSuccessStatusCode in Ihrem Namen aufrufen. Betrachten Sie die folgenden APIs:

Tipp

Alle HttpClient-Methoden, die für HTTP-Anforderungen verwendet werden und keine HttpResponseMessage zurückgeben, rufen implizit EnsureSuccessStatusCode in Ihrem Namen auf.

Beim Aufruf dieser Methoden können Sie HttpRequestException behandeln und die Eigenschaft HttpRequestException.StatusCode auswerten, um den HTTP-Statuscode der Antwort zu bestimmen:

try
{
    // These extension methods will throw HttpRequestException
    // with StatusCode set when the HTTP request status code isn't 2xx:
    //
    //   GetByteArrayAsync
    //   GetStreamAsync
    //   GetStringAsync

    using var stream = await httpClient.GetStreamAsync(
        "https://localhost:5001/doesNotExists");
}
catch (HttpRequestException ex) when (ex is { StatusCode: HttpStatusCode.NotFound })
{
    // Handle 404
    Console.WriteLine($"Not found: {ex.Message}");
}

Es kann Szenarien geben, in denen Sie HttpRequestException in Ihrem Code verwenden müssen. Der HttpRequestException()-Konstruktor ist öffentlich, und Sie können ihn dazu verwenden, eine Ausnahme mit einer benutzerdefinierten Meldung auszulösen:

try
{
    using var response = await httpClient.GetAsync(
        "https://localhost:5001/doesNotExists");

    // Throw for anything higher than 400.
    if (response is { StatusCode: >= HttpStatusCode.BadRequest })
    {
        throw new HttpRequestException(
            "Something went wrong", inner: null, response.StatusCode);
    }
}
catch (HttpRequestException ex) when (ex is { StatusCode: HttpStatusCode.NotFound })
{
    Console.WriteLine($"Not found: {ex.Message}");
}

HTTP-Proxy

Ein HTTP-Proxy kann auf zwei Arten konfiguriert werden. Für die Eigenschaft HttpClient.DefaultProxy wird ein Standardwert festgelegt. Alternativ können Sie einen Proxy für die Eigenschaft HttpClientHandler.Proxy angeben.

Globaler Standardproxy

HttpClient.DefaultProxy ist eine statische Eigenschaft zum Festlegen des Standardproxys, der von allen HttpClient-Instanzen verwendet wird, wenn in dem durch seinen Konstruktor übergebenen HttpClientHandler nicht explizit ein Proxy festgelegt wurde.

Die über diese Eigenschaft zurückgegebene Standardinstanz wird abhängig von Ihrer Plattform nach unterschiedlichen Regeln initialisiert:

  • Für Windows: Die Proxykonfiguration wird aus den Umgebungsvariablen gelesen, sofern definiert. Andernfalls wird sie aus den Proxyeinstellungen der Benutzer*innen gelesen.
  • Für macOS: Die Proxykonfiguration wird aus den Umgebungsvariablen gelesen, sofern definiert. Andernfalls wird sie aus den Proxyeinstellungen des Systems gelesen.
  • Für Linux: Die Proxykonfiguration wird aus den Umgebungsvariablen gelesen, sofern definiert. Andernfalls initialisiert diese Eigenschaft eine nicht konfigurierte Instanz, die alle Adressen umgeht.

Für die Initialisierung von DefaultProxy auf Windows- und Unix-basierten Plattformen werden folgende Umgebungsvariablen verwendet:

  • HTTP_PROXY: Der für HTTP-Anforderungen verwendete Proxyserver.
  • HTTPS_PROXY: Der für HTTPS-Anforderungen verwendete Proxyserver.
  • ALL_PROXY: Der für HTTP- und/oder HTTPS-Anforderungen verwendete Proxyserver, falls HTTP_PROXY und/oder HTTPS_PROXY nicht definiert sind.
  • NO_PROXY: Eine durch Trennzeichen getrennte Liste mit Hostnamen, die aus der Proxyfunktion ausgeschlossen werden sollen. Sternchen werden nicht als Platzhalter unterstützt. Verwenden Sie einen vorangestellten Punkt, wenn Sie eine Unterdomäne abgleichen möchten. Beispiele: NO_PROXY=.example.com (mit vorangestelltem Punkt) führt zu einer Übereinstimmung mit www.example.com, nicht jedoch mit example.com. NO_PROXY=example.com (ohne vorangestelltem Punkt) führt nicht zu einer Übereinstimmung mit www.example.com. Dieses Verhalten könnte in Zukunft überarbeitet werden, um anderen Ökosystemen besser zu entsprechen.

Bei Systemen, bei denen bei Umgebungsvariablen die Groß-/Kleinschreibung beachtet wird, bestehen die Variablennamen unter Umständen nur aus Kleinbuchstaben oder nur aus Großbuchstaben. Die Namen in Kleinbuchstaben werden zuerst überprüft.

Der Proxyserver kann ein Hostname oder eine IP-Adresse sein, optional gefolgt von einem Doppelpunkt und einer Portnummer. Alternativ kann es sich um eine http-URL handeln, die optional einen Benutzernamen und ein Kennwort für die Proxyauthentifizierung umfasst. Die URL muss mit http beginnen (nicht mit https) und darf nach dem Hostnamen, der IP-Adresse oder dem Port keinen Text enthalten.

Proxy pro Client

Die Eigenschaft HttpClientHandler.Proxy identifiziert das WebProxy-Objekt, das zum Verarbeiten von Anforderungen an Internetressourcen verwendet wird. Um anzugeben, dass kein Proxy verwendet werden soll, legen Sie die Eigenschaft Proxy auf die Proxyinstanz fest, die von der Methode GlobalProxySelection.GetEmptyWebProxy() zurückgegeben wird.

In der Konfigurationsdatei des lokalen Computers oder der Anwendung kann angegeben werden, dass ein Standardproxy verwendet werden soll. Wenn die Proxy-Eigenschaft angegeben wurde, haben die Proxyeinstellungen aus der Proxy-Eigenschaft Vorrang vor der Konfigurationsdatei des lokalen Computers oder der Anwendung, und der Handler verwendet die angegebenen Proxyeinstellungen. Wenn in der Konfigurationsdatei kein Proxy angegeben ist und die Proxy-Eigenschaft nicht festgelegt wurde, verwendet der Handler die vom lokalen Computer geerbten Proxyeinstellungen. Wenn keine Proxyeinstellungen vorhanden sind, wird die Anforderung direkt an den Server gesendet.

Die Klasse HttpClientHandler analysiert eine Proxyumgehungsliste mit Platzhaltern, die von den lokalen Computereinstellungen übernommen wurden. Beispielsweise analysiert die Klasse HttpClientHandler eine Umgehungsliste "nt*" aus Browsern als regulären Ausdruck von "nt.*". Somit würde die URL http://nt.com den Proxy mit der Klasse HttpClientHandler umgehen.

Die HttpClientHandler-Klasse unterstützt die lokale Proxyumgehung. Die Klasse betrachtet ein Ziel als lokal, wenn eine der folgenden Bedingungen erfüllt ist:

  1. Das Ziel enthält einen flachen Namen (keine Punkte in der URL).
  2. Das Ziel enthält eine Loopbackadresse (Loopback oder IPv6Loopback), oder das Ziel enthält eine IPAddress, die dem lokalen Computer zugewiesen ist.
  3. Das Domänensuffix des Ziels entspricht dem Domänensuffix des lokalen Computers (DomainName).

Weitere Informationen zum Konfigurieren eines Proxys finden Sie hier:

Weitere Informationen