Sprawdzanie, czy HttpStatusCode reprezentuje sukces, czy niepowodzenie

94

Załóżmy, że mam następującą zmienną:

System.Net.HttpStatusCode status = System.Net.HttpStatusCode.OK;

Jak mogę sprawdzić, czy jest to kod statusu sukcesu, czy błąd?

Na przykład mogę wykonać następujące czynności:

int code = (int)status;
if(code >= 200 && code < 300) {
    //Success
}

Mogę też mieć jakąś białą listę:

HttpStatusCode[] successStatus = new HttpStatusCode[] {
     HttpStatusCode.OK,
     HttpStatusCode.Created,
     HttpStatusCode.Accepted,
     HttpStatusCode.NonAuthoritativeInformation,
     HttpStatusCode.NoContent,
     HttpStatusCode.ResetContent,
     HttpStatusCode.PartialContent
};
if(successStatus.Contains(status)) //LINQ
{
    //Success
}

Żadna z tych alternatyw mnie nie przekonuje i liczyłem na klasę lub metodę .NET, która może wykonać tę pracę za mnie, na przykład:

bool isSuccess = HttpUtilities.IsSuccess(status);
Matias Cicero
źródło
musisz to zrobić int code = (int)Response.StatusCodestamtąd będziesz musiał utworzyć swój własny Enumczek tutaj dla przykładu roboczego stackoverflow.com/questions/1330856/ ...
MethodMan
Czy przypadkiem korzystasz z tej HttpClientklasy?
dcastro
1
@dcastro Nie, przepraszam. Używam interfejsu API wysokiego poziomu, który może (ale nie musi) używać go wewnętrznie. API ujawnia kod stanu odpowiedzi, ale nie ujawnia HttpResponseMessagena przykład wewnętrznego
Matias Cicero
@MatiCicero Szkoda: / Zawsze możesz ponownie użyć implementacji HttpResponseMessage.IsSuccessStatusCode(zobacz moją odpowiedź), która jest dokładnie taka sama jak w przypadku pierwszego podejścia, i uczynić ją metodą rozszerzającą dla HttpStatusCodetypu.
dcastro

Odpowiedzi:

178

Jeśli korzystasz z HttpClientklasy, otrzymasz HttpResponseMessagezwrot.

Ta klasa ma użyteczną właściwość o nazwie, IsSuccessStatusCodektóra wykona sprawdzenie za Ciebie.

using (var client = new HttpClient())
{
    var response = await client.PostAsync(uri, content);
    if (response.IsSuccessStatusCode)
    {
        //...
    }
}

Jeśli jesteś ciekawy, ta właściwość jest zaimplementowana jako:

public bool IsSuccessStatusCode
{
    get { return ((int)statusCode >= 200) && ((int)statusCode <= 299); }
}

Możesz więc po prostu ponownie użyć tego algorytmu, jeśli nie używasz go HttpClientbezpośrednio.

Możesz również użyć, EnsureSuccessStatusCodeaby zgłosić wyjątek w przypadku, gdy odpowiedź nie powiodła się.

dcastro
źródło
1
FYI: To była dla mnie odpowiedź.
Narodziny
Twoja odpowiedź jest bardzo pomocna, ale teraz działa tak: if (response.IsCompletedSuccessfully) {//}
salman
12

Klasa HttpResponseMessage ma właściwość IsSuccessStatusCode, patrząc na kod źródłowy wygląda to tak, ponieważ usr zasugerował już, że 200-299 to prawdopodobnie najlepsze, co możesz zrobić.

public bool IsSuccessStatusCode
{
    get { return ((int)statusCode >= 200) && ((int)statusCode <= 299); }
}
TomDoesCode
źródło
11

Przyjęta odpowiedź trochę mnie niepokoi, bo w drugiej części zawiera magiczne liczby (choć są w standardzie). Pierwsza część nie jest ogólna dla kodów stanu w postaci liczb całkowitych, chociaż jest bliska mojej odpowiedzi.

Możesz osiągnąć dokładnie ten sam wynik, tworząc wystąpienie HttpResponseMessage z kodem statusu i sprawdzając, czy powodzenie. Rzuca wyjątek argumentu, jeśli wartość jest mniejsza od zera lub większa niż 999.

if (new HttpResponseMessage((HttpStatusCode)statusCode).IsSuccessStatusCode)
{
    // ...
}

Nie jest to do końca zwięzłe, ale możesz zrobić z tego rozszerzenie.

user232548
źródło
To zadziałało idealnie dla mnie, ponieważ miałem tylko HttpStatusCode, a nie komunikat odpowiedzi. Dobra robota!
Todd Vance
5
„Przyjęta odpowiedź trochę mnie niepokoi, ponieważ zawiera magiczne liczby (chociaż są w standardzie)” - Nie są „magiczne”, jeśli są ustandaryzowane, dobrze zrozumiane i nigdy się nie zmienią. Nie ma absolutnie nic złego w używaniu kodów bezpośrednio. Jeśli masz IsSuccessStatusCodeto świetne, użyj go (zgodnie z akceptowaną odpowiedzią). W przeciwnym razie nie dodawaj własnego cruft za pomocą abstrakcji, chyba że wykonujesz to sprawdzanie wszędzie
Ed S.
1
Pamiętaj, że utworzenie wystąpienia w HttpResponseMessagecelu użycia jednej z jego właściwości zajmuje więcej czasu niż sprawdzenie dwóch warunków logicznych za pomocą int.
Miro J.
10

Dodawanie do odpowiedzi @TomDoesCode Jeśli używasz HttpWebResponse, możesz dodać tę metodę rozszerzenia:

public static bool IsSuccessStatusCode(this HttpWebResponse httpWebResponse)
{
    return ((int)httpWebResponse.StatusCode >= 200) && ((int)httpWebResponse.StatusCode <= 299);
}
ozba
źródło
8

Jestem zwolennikiem wykrywalności metod rozszerzających.

public static class HttpStatusCodeExtensions
{
    public static bool IsSuccessStatusCode(this HttpStatusCode statusCode)
    {
        var asInt = (int)statusCode;
        return asInt >= 200 && asInt <= 299;
    }
}

Dopóki przestrzeń nazw znajduje się w zakresie, użycie będzie statusCode.IsSuccessStatusCode().

bojingo
źródło
Metody rozszerzające są fajne, ale jestem zdezorientowany - czy nie robi to tego samego, co właściwość IsSuccessStatusCode protokołu HTTPResponseMessage, która jest używana z HTTPClient lub IHTTPClientFactory? @DCastro pokazuje nam nawet, że jest zaimplementowany dokładnie tak samo w .NET. Kiedy / dlaczego miałbym używać takiej metody rozszerzenia dla kodów stanu HTTP z zakresu 2xx?
sfors mówi, że przywróć Monikę
4
@sfors, tak, ale co, jeśli masz tylko HttpStatusCodezakres? Istnieje wiele bibliotek, które nie używają ani HttpResponseMessagenie wyświetlają się, ale podają kod statusu.
bojingo
3

Zależy to od wywoływanego zasobu HTTP. Zwykle 2xxzakres jest definiowany jako zakres kodów statusu sukcesu. Jest to oczywiście konwencja, której nie będzie przestrzegać każdy serwer HTTP.

Na przykład przesłanie formularza w witrynie internetowej często zwraca przekierowanie 302.

Jeśli chcesz opracować ogólną metodę, code >= 200 && code < 300pomysł jest prawdopodobnie najlepszym rozwiązaniem.

Jeśli dzwonisz na swój własny serwer, prawdopodobnie powinieneś upewnić się, że używasz standardu 200.

usr
źródło
2

Jest to rozszerzenie poprzedniej odpowiedzi, które pozwala uniknąć tworzenia i późniejszego czyszczenia nowego obiektu dla każdego wywołania.

public static class StatusCodeExtensions
{
    private static readonly ConcurrentDictionary<HttpStatusCode, bool> IsSuccessStatusCode = new ConcurrentDictionary<HttpStatusCode, bool>();
    public static bool IsSuccess(this HttpStatusCode statusCode) => IsSuccessStatusCode.GetOrAdd(statusCode, c => new HttpResponseMessage(c).IsSuccessStatusCode);
}
Rob Lyndon
źródło