Saltar al contenido

Mejores prácticas para devolver errores en ASP.NET Web API

Te damos la bienvenida a proyecto online, ahora vas a hallar la resolución a lo que buscabas.

Solución:

Para mí, generalmente envío un HttpResponseException y configure el código de estado según la excepción lanzada y si la excepción es fatal o no determinará si devuelvo el HttpResponseException inmediatamente.

Al final del día, es una API que envía respuestas y no vistas, por lo que creo que está bien enviar un mensaje con la excepción y el código de estado al consumidor. Actualmente no he necesitado acumular errores y devolverlos, ya que la mayoría de las excepciones generalmente se deben a parámetros o llamadas incorrectos, etc.

Un ejemplo en mi aplicación es que a veces el cliente solicita datos, pero no hay datos disponibles, así que lanzo un mensaje personalizado. NoDataAvailableException y déjelo burbujear en la aplicación Web API, donde luego en mi filtro personalizado lo captura enviando un mensaje relevante junto con el código de estado correcto.

No estoy 100% seguro de cuál es la mejor práctica para esto, pero actualmente me está funcionando, así que eso es lo que estoy haciendo.

Actualizar:

Desde que respondí esta pregunta, se han escrito algunas publicaciones de blog sobre el tema:

https://weblogs.asp.net/fredriknormen/asp-net-web-api-exception-handling

(este tiene algunas características nuevas en las compilaciones nocturnas) https://docs.microsoft.com/archive/blogs/youssefm/error-handling-in-asp-net-webapi

Actualización 2

Actualización a nuestro proceso de manejo de errores, tenemos dos casos:

  1. Para errores generales como no encontrado o parámetros no válidos que se pasan a una acción, devolvemos un HttpResponseException para detener el procesamiento inmediatamente. Además, para los errores del modelo en nuestras acciones, entregaremos el diccionario de estado del modelo al Request.CreateErrorResponse extensión y envuélvalo en una HttpResponseException. Agregar el diccionario de estado del modelo da como resultado una lista de los errores del modelo enviados en el cuerpo de la respuesta.

  2. Para los errores que ocurren en capas superiores, errores del servidor, dejamos que la excepción burbujee en la aplicación Web API, aquí tenemos un filtro de excepción global que analiza la excepción, la registra con ELMAH e intenta encontrarle sentido configurando el HTTP correcto código de estado y un mensaje de error amigable relevante como el cuerpo nuevamente en un HttpResponseException. Para las excepciones que no esperamos, el cliente recibirá el error interno del servidor 500 predeterminado, pero un mensaje genérico por razones de seguridad.

Actualización 3

Recientemente, después de elegir Web API 2, para devolver errores generales, ahora usamos la interfaz IHttpActionResult, específicamente las clases integradas en el System.Web.Http.Results espacio de nombres como NotFound, BadRequest cuando encajan, si no lo hacen, los ampliamos, por ejemplo, un resultado NotFound con un mensaje de respuesta:

public class NotFoundWithMessageResult : IHttpActionResult

    private string message;

    public NotFoundWithMessageResult(string message)
    
        this.message = message;
    

    public Task ExecuteAsync(CancellationToken cancellationToken)
    
        var response = new HttpResponseMessage(HttpStatusCode.NotFound);
        response.Content = new StringContent(message);
        return Task.FromResult(response);
    

ASP.NET Web API 2 realmente lo simplificó. Por ejemplo, el siguiente código:

public HttpResponseMessage GetProduct(int id)

    Product item = repository.Get(id);
    if (item == null)
    
        var message = string.Format("Product with id = 0 not found", id);
        HttpError err = new HttpError(message);
        return Request.CreateResponse(HttpStatusCode.NotFound, err);
    
    else
    
        return Request.CreateResponse(HttpStatusCode.OK, item);
    

devuelve el siguiente contenido al navegador cuando no se encuentra el elemento:

HTTP/1.1 404 Not Found
Content-Type: application/json; charset=utf-8
Date: Thu, 09 Aug 2012 23:27:18 GMT
Content-Length: 51


  "Message": "Product with id = 12 not found"

Sugerencia: no arroje el error HTTP 500 a menos que haya un error catastrófico (por ejemplo, WCF Fault Exception). Elija un código de estado HTTP apropiado que represente el estado de sus datos. (Vea el enlace de apigee a continuación).

Enlaces:

  • Manejo de excepciones en ASP.NET Web API (asp.net) y
  • Diseño de API RESTful: ¿qué pasa con los errores? (apigee.com)

Parece que tiene más problemas con la Validación que con los errores/excepciones, así que hablaré un poco sobre ambos.

Validación

Las acciones del controlador generalmente deben tomar modelos de entrada donde la validación se declara directamente en el modelo.

public class Customer
 
    [Require]
    public string Name  get; set; 

Entonces puedes usar un ActionFilter que envía automáticamente mensajes de validación al cliente.

public class ValidationActionFilter : ActionFilterAttribute

    public override void OnActionExecuting(HttpActionContext actionContext)
    
        var modelState = actionContext.ModelState;

        if (!modelState.IsValid) 
            actionContext.Response = actionContext.Request
                 .CreateErrorResponse(HttpStatusCode.BadRequest, modelState);
        
    
 

Para obtener más información sobre esto, consulte http://ben.onfabrik.com/posts/automatic-modelstate-validation-in-aspnet-mvc

Manejo de errores

Lo mejor es devolver un mensaje al cliente que represente la excepción que ocurrió (con el código de estado relevante).

Fuera de la caja tienes que usar Request.CreateErrorResponse(HttpStatusCode, message) si desea especificar un mensaje. Sin embargo, esto vincula el código con el Request objeto, que no debería necesitar hacer.

Por lo general, creo mi propio tipo de excepción “segura” que espero que el cliente sepa cómo manejar y envolver a todos los demás con un error genérico 500.

El uso de un filtro de acción para manejar las excepciones se vería así:

public class ApiExceptionFilterAttribute : ExceptionFilterAttribute

    public override void OnException(HttpActionExecutedContext context)
    
        var exception = context.Exception as ApiException;
        if (exception != null) 
            context.Response = context.Request.CreateErrorResponse(exception.StatusCode, exception.Message);
        
    

Entonces puedes registrarlo globalmente.

GlobalConfiguration.Configuration.Filters.Add(new ApiExceptionFilterAttribute());

Este es mi tipo de excepción personalizado.

using System;
using System.Net;

namespace WebApi

    public class ApiException : Exception
    
        private readonly HttpStatusCode statusCode;

        public ApiException (HttpStatusCode statusCode, string message, Exception ex)
            : base(message, ex)
        
            this.statusCode = statusCode;
        

        public ApiException (HttpStatusCode statusCode, string message)
            : base(message)
        
            this.statusCode = statusCode;
        

        public ApiException (HttpStatusCode statusCode)
        
            this.statusCode = statusCode;
        

        public HttpStatusCode StatusCode
        
            get  return this.statusCode; 
        
    

Una excepción de ejemplo que mi API puede lanzar.

public class NotAuthenticatedException : ApiException

    public NotAuthenticatedException()
        : base(HttpStatusCode.Forbidden)
    
    

Recuerda que tienes la capacidad de valorar este post si te fue preciso.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *