Verwendung von EnsureSuccessStatusCode und Behandlung der ausgelösten HttpRequestException

103

Was ist das Nutzungsmuster von HttpResponseMessage.EnsureSuccessStatusCode()? Es verfügt über den Inhalt der Nachricht und wirft HttpRequestException, aber ich sehe nicht ein, wie ich programmgesteuert anders damit umgehen soll als mit einem Generikum Exception. Zum Beispiel enthält es nicht das HttpStatusCode, was praktisch gewesen wäre.

Gibt es eine Möglichkeit, mehr Informationen daraus zu ziehen? Könnte jemand das relevante Verwendungsmuster von sowohl EnsureSuccessStatusCode()HttpRequestException als auch HttpRequestException anzeigen?

G. Stoynev
quelle

Antworten:

155

Die idiomatische Verwendung von EnsureSuccessStatusCodebesteht darin, den Erfolg einer Anforderung genau zu überprüfen, wenn Sie Fehlerfälle nicht auf eine bestimmte Weise behandeln möchten. Dies ist besonders nützlich, wenn Sie einen Client schnell prototypisieren möchten.

Führen Sie die folgenden Schritte nicht aus, wenn Sie sich entscheiden, Fehlerfälle auf bestimmte Weise zu behandeln .

var response = await client.GetAsync(...);
try
{
    response.EnsureSuccessStatusCode();
    // Handle success
}
catch (HttpRequestException)
{
    // Handle failure
}

Dies löst eine Ausnahme aus, um sie sofort zu erfassen, was keinen Sinn ergibt. Das IsSuccessStatusCodeEigentum von HttpResponseMessageist zu diesem Zweck vorhanden. Gehen Sie stattdessen wie folgt vor.

var response = await client.GetAsync(...);
if (response.IsSuccessStatusCode)
{
    // Handle success
}
else
{
    // Handle failure
}
Timothy Shields
quelle
1
Gibt es eine Möglichkeit, den Statuscode für echte Ganzzahlen abzurufen? Wenn ich dies versuche, erhalte ich eine Zeichenfolge wie "NotFound" anstelle des 404-Statuscodes.
NickG
12
@ NickG (int)response.StatusCode(Siehe msdn.microsoft.com/en-us/library/… )
Timothy Shields
1
Beachten Sie, dass die von EnsureSuccessStatusCode () ausgelöste Standard-HttpRequestException die Grundphrase enthält. Sie können jedoch trotzdem in der Antwort auf diese Eigenschaft zugreifen, wenn sie nicht erfolgreich ist.
Stefan Zvonar
@StefanZvonar Ich kann den Grundsatz in der Ausnahme nicht so finden, wie Sie ihn geschrieben haben.
KansaiRobot
1
@ NickG Sie können (int) response.StatusCode verwenden, um den numerischen Wert für den HTTP-Statuscode abzurufen
Henrik Holmgaard Høyer
95

Ich mag EnsureSuccessStatusCode nicht, da es nichts Sinnvolles zurückgibt. Deshalb habe ich meine eigene Erweiterung erstellt:

public static class HttpResponseMessageExtensions
{
    public static async Task EnsureSuccessStatusCodeAsync(this HttpResponseMessage response)
    {
        if (response.IsSuccessStatusCode)
        {
            return;
        }

        var content = await response.Content.ReadAsStringAsync();

        if (response.Content != null)
            response.Content.Dispose();

        throw new SimpleHttpResponseException(response.StatusCode, content);
    }
}

public class SimpleHttpResponseException : Exception
{
    public HttpStatusCode StatusCode { get; private set; }

    public SimpleHttpResponseException(HttpStatusCode statusCode, string content) : base(content)
    {
        StatusCode = statusCode;
    }
}

Der Quellcode für den EnsureSuccessStatusCode von Microsoft ist zu finden hier

Synchrone Version basierend auf SO-Link :

public static void EnsureSuccessStatusCode(this HttpResponseMessage response)
{
    if (response.IsSuccessStatusCode)
    {
        return;
    }

    var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();

    if (response.Content != null)
        response.Content.Dispose();

    throw new SimpleHttpResponseException(response.StatusCode, content);
}

Was ich an IsSuccessStatusCode nicht mag, ist, dass es nicht "schön" wiederverwendbar ist. Beispielsweise können Sie eine Bibliothek wie polly verwenden , um eine Anforderung im Falle eines Netzwerkproblems zu wiederholen. In diesem Fall muss Ihr Code eine Ausnahme auslösen, damit polly oder eine andere Bibliothek damit umgehen kann ...

pajics
quelle
1
stimme zu, dem Standardcode fehlt die Funktion, um eine aussagekräftige Nachricht von der Rückgabe zu erhalten.
LT
2
Ihre Version funktioniert anders als die ursprüngliche Implementierung von EnsureSuccessStatusCode. Sie entsorgen das immer response.Content(weil schließlich auch nach der return;Anweisung immer aufgerufen wird ) und es zerstört den Inhalt zum weiteren Lesen. Die ursprüngliche Implementierung entsorgt den Inhalt nur, wenn der Statuscode kein erfolgreiches Ergebnis anzeigt.
Lukas.Navratil
4
Ich verstehe nicht, warum Sie zuerst await response.Content.ReadAsStringAsync()und dann überprüfenif (response.Content != null)
Mafu
3
Polly behandelt jetzt sowohl Rückgabeergebnisse als auch Ausnahmen, um genau diese Art von Szenario zu unterstützen. Sie können Polly so konfigurieren, dass HttpRequestAnrufe geschützt werden, und die Richtlinie so konfigurieren, dass sowohl bestimmte Ausnahmen als auch bestimmte HttpResponseCodes behandelt werden. Sehen Sie das Beispiel in der Polly readme hier
Berg Reisenden
2
Wie könnte response.Contentnull sein, wenn gerade eine Methode aufgerufen wurde?
Ian Warburton
1

Ich verwende EnsureSuccessStatusCode, wenn ich die Ausnahme nicht mit derselben Methode behandeln möchte.

public async Task DoSomethingAsync(User user)
{
    try
    {
        ...
        var userId = await GetUserIdAsync(user)
        ...
    }
    catch(Exception e)
    {
        throw;
    }
}

public async Task GetUserIdAsync(User user)
{
    using(var client = new HttpClient())
    {
        ...
        response = await client.PostAsync(_url, context);

        response.EnsureSuccesStatusCode();
        ...
    }
}

Die auf GetUserIdAsync ausgelöste Ausnahme wird auf DoSomethingAsync behandelt.

Sérgio Damasceno
quelle