Comprobando si HttpStatusCode representa éxito o fracaso

93

Supongamos que tengo la siguiente variable:

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

¿Cómo puedo comprobar si se trata de un código de estado de éxito o de fallo?

Por ejemplo, puedo hacer lo siguiente:

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

También puedo tener algún tipo de lista blanca:

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

Ninguna de estas alternativas me convence, y esperaba una clase o método .NET que pudiera hacer este trabajo por mí, como:

bool isSuccess = HttpUtilities.IsSuccess(status);
Matias Cicero
fuente
debe hacerlo int code = (int)Response.StatusCodedesde allí, deberá crear su propio Enumcheque aquí para el ejemplo de trabajo stackoverflow.com/questions/1330856/…
MethodMan
¿Por casualidad estás usando la HttpClientclase?
dcastro
1
@dcastro No, lo siento. Estoy usando una API de alto nivel que puede (o no) usarla internamente. La API expone el código de estado de la respuesta, pero no expone el interior, HttpResponseMessagepor ejemplo
Matias Cicero
@MatiCicero Eso es una lástima: / Siempre puede reutilizar la implementación de HttpResponseMessage.IsSuccessStatusCode(vea mi respuesta), que es exactamente la misma que su primer enfoque, y convertirla en un método de extensión en el HttpStatusCodetipo.
dcastro

Respuestas:

173

Si estás usando la HttpClientclase, obtendrás un HttpResponseMessagerespaldo.

Esta clase tiene una propiedad útil llamada IsSuccessStatusCodeque hará la verificación por usted.

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

En caso de que tenga curiosidad, esta propiedad se implementa como:

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

Por lo que sólo puede volver a utilizar este algoritmo si estás no usar HttpClientdirectamente.

También puede usar EnsureSuccessStatusCodepara lanzar una excepción en caso de que la respuesta no haya sido exitosa.

dcastro
fuente
FYI: Fue 'respuesta. Es exitosa' para mí.
Nacimiento de Topher
Su respuesta es bastante útil, pero ahora funciona así: if (response.IsCompletedSuccessfully) {//}
salman
12

La clase HttpResponseMessage tiene una propiedad IsSuccessStatusCode, mirando el código fuente es así, como usr ya ha sugerido que 200-299 es probablemente lo mejor que puede hacer.

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

La respuesta aceptada me molesta un poco ya que contiene números mágicos, (aunque están en estándar) en su segunda parte. Y la primera parte no es genérica para los códigos de estado enteros simples, aunque está cerca de mi respuesta.

Puede lograr exactamente el mismo resultado creando una instancia de HttpResponseMessage con su código de estado y verificando el éxito. Lanza una excepción de argumento si el valor es menor que cero o mayor que 999.

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

Esto no es exactamente conciso, pero podría convertirlo en una extensión.

usuario232548
fuente
Esto funcionó perfectamente para mí, ya que solo tenía un HttpStatusCode y no un mensaje de respuesta. ¡Buen trabajo!
Todd Vance
5
"La respuesta aceptada me molesta un poco porque contiene números mágicos, (aunque están en estándar)" - No son "mágicos" si están estandarizados, bien comprendidos y nunca van a cambiar. No hay absolutamente nada de malo en usar los códigos directamente. Si lo ha hecho IsSuccessStatusCodegenial, úselo (como dice la respuesta aceptada). De lo contrario, no agregue su propio cruft utilizando una abstracción a menos que esté realizando esta verificación por todas partes
Ed S.
1
Tenga en cuenta que crear instancias HttpResponseMessagepara usar una de sus propiedades lleva más tiempo que verificar dos condiciones lógicas con int.
Miro J.
10

Agregar a la respuesta de @TomDoesCode Si está utilizando HttpWebResponse, puede agregar este método de extensión:

public static bool IsSuccessStatusCode(this HttpWebResponse httpWebResponse)
{
    return ((int)httpWebResponse.StatusCode >= 200) && ((int)httpWebResponse.StatusCode <= 299);
}
ozba
fuente
8

Soy partidario de la posibilidad de descubrir los métodos de extensión.

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

Siempre que su espacio de nombres esté dentro del alcance, el uso sería statusCode.IsSuccessStatusCode().

bojingo
fuente
2
probablemente quieras un AsInt> = 200 allí
Jim O'Neil
Los métodos de extensión son geniales, pero estoy confundido: ¿no hace esto lo mismo que la propiedad IsSuccessStatusCode de HTTPResponseMessage que se usa con HTTPClient o IHTTPClientFactory? @DCastro incluso nos muestra que está implementado exactamente así en .NET. ¿Cuándo / por qué debería usar un método de extensión como este para los códigos de estado HTTP en el rango 2xx?
sfors dice reinstalar a Monica
4
@sfors, sí, pero ¿y si solo tienes un HttpStatusCodealcance? Hay muchas bibliotecas que no usan ni HttpResponseMessageaparecen, pero le brindan el código de estado.
bojingo
3

Depende del recurso HTTP al que llame. Por lo general, el 2xxrango se define como el rango de códigos de estado de éxito. Esa es claramente una convención a la que no se adherirán todos los servidores HTTP.

Por ejemplo, enviar un formulario en un sitio web a menudo devolverá un redireccionamiento 302.

Si desea idear un método general, la code >= 200 && code < 300idea probablemente sea su mejor opción.

Si está llamando a su propio servidor, probablemente debería asegurarse de estandarizar 200.

usr
fuente
2

Esta es una extensión de la respuesta anterior, que evita la creación y posterior recolección de basura de un nuevo objeto para cada invocación.

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
fuente