Zpracování výjimek ve webovém rozhraní API ASP.NET

Tento článek popisuje zpracování chyb a výjimek ve webovém rozhraní API ASP.NET.

HttpResponseException

Co se stane, když kontroler webového rozhraní API vyvolá nezachycenou výjimku? Ve výchozím nastavení se většina výjimek překládá do odpovědi HTTP se stavovým kódem 500– Vnitřní chyba serveru.

Typ HttpResponseException je speciální případ. Tato výjimka vrátí jakýkoli stavový kód HTTP, který zadáte v konstruktoru výjimky. Například následující metoda vrátí 404, Nenalezena, pokud parametr id není platný.

public Product GetProduct(int id)
{
    Product item = repository.Get(id);
    if (item == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }
    return item;
}

Pokud chcete mít větší kontrolu nad odpovědí, můžete také vytvořit celou zprávu odpovědi a zahrnout ji do výjimky HttpResponseException:

public Product GetProduct(int id)
{
    Product item = repository.Get(id);
    if (item == null)
    {
        var resp = new HttpResponseMessage(HttpStatusCode.NotFound)
        {
            Content = new StringContent(string.Format("No product with ID = {0}", id)),
            ReasonPhrase = "Product ID Not Found"
        };
        throw new HttpResponseException(resp);
    }
    return item;
}

Filtry výjimek

Způsob, jakým webové rozhraní API zpracovává výjimky, můžete přizpůsobit tak, že napíšete filtr výjimek. Filtr výjimky se spustí, když metoda kontroleru vyvolá jakoukoli neošetřenou výjimku, která není výjimkou HttpResponseException . Typ HttpResponseException je speciální případ, protože je navržen speciálně pro vrácení odpovědi HTTP.

Filtry výjimek implementují rozhraní System.Web.Http.Filters.IExceptionFilter . Nejjednodušší způsob, jak napsat filtr výjimek, je odvození z třídy System.Web.Http.Filters.ExceptionFilterAttribute a přepsání Metody OnException .

Poznámka

Filtry výjimek ve webovém rozhraní API ASP.NET jsou podobné filtrům v ASP.NET MVC. Jsou však deklarovány v samostatném oboru názvů a fungují samostatně. Konkrétně třída HandleErrorAttribute používaná v MVC nezpracovává výjimky vyvolané kontrolery webového rozhraní API.

Tady je filtr, který převádí výjimky NotImplementedException na stavový kód HTTP 501, Není implementováno:

namespace ProductStore.Filters
{
    using System;
    using System.Net;
    using System.Net.Http;
    using System.Web.Http.Filters;

    public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute 
    {
        public override void OnException(HttpActionExecutedContext context)
        {
            if (context.Exception is NotImplementedException)
            {
                context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
            }
        }
    }
}

Vlastnost Responseobjektu HttpActionExecutedContext obsahuje zprávu odpovědi HTTP, která bude odeslána klientovi.

Registrace filtrů výjimek

Filtr výjimek webového rozhraní API můžete zaregistrovat několika způsoby:

  • Podle akce
  • Podle kontroleru
  • Globálně

Pokud chcete filtr použít na konkrétní akci, přidejte filtr jako atribut akce:

public class ProductsController : ApiController
{
    [NotImplExceptionFilter]
    public Contact GetContact(int id)
    {
        throw new NotImplementedException("This method is not implemented");
    }
}

Pokud chcete filtr použít na všechny akce v kontroleru, přidejte filtr jako atribut do třídy kontroleru:

[NotImplExceptionFilter]
public class ProductsController : ApiController
{
    // ...
}

Pokud chcete filtr použít globálně na všechny kontrolery webového rozhraní API, přidejte instanci filtru do kolekce GlobalConfiguration.Configuration.Filters . Filtry výjimek v této kolekci se vztahují na všechny akce kontroleru webového rozhraní API.

GlobalConfiguration.Configuration.Filters.Add(
    new ProductStore.NotImplExceptionFilterAttribute());

Pokud k vytvoření projektu použijete šablonu projektu "webová aplikace ASP.NET MVC 4", vložte konfigurační kód webového WebApiConfig rozhraní API do třídy, která se nachází ve složce App_Start:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Filters.Add(new ProductStore.NotImplExceptionFilterAttribute());

        // Other configuration code...
    }
}

Chyba http

Objekt HttpError poskytuje konzistentní způsob, jak vracet informace o chybě v textu odpovědi. Následující příklad ukazuje, jak vrátit stavový kód HTTP 404 (Nenalezena) s chybou Http v těle odpovědi.

public HttpResponseMessage GetProduct(int id)
{
    Product item = repository.Get(id);
    if (item == null)
    {
        var message = string.Format("Product with id = {0} not found", id);
        return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
    }
    else
    {
        return Request.CreateResponse(HttpStatusCode.OK, item);
    }
}

CreateErrorResponse je rozšiřující metoda definovaná ve třídě System.Net.Http.HttpRequestMessageExtensions . Interně CreateErrorResponse vytvoří instanci HttpError a poté vytvoří HttpResponseMessage , která obsahuje HttpError.

Pokud je v tomto příkladu metoda úspěšná, vrátí produkt v odpovědi HTTP. Pokud se ale požadovaný produkt nenajde, odpověď HTTP obsahuje v textu požadavku chybu HttpError . Odpověď může vypadat takto:

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"
}

Všimněte si, že v tomto příkladu byla chyba HttpError serializována do formátu JSON. Jednou z výhod použití HttpError je, že prochází stejným procesem vyjednávání a serializace obsahu jako jakýkoli jiný model silného typu.

Chyba http a ověření modelu

Pro ověření modelu můžete předat stav modelu createErrorResponse, aby se do odpovědi zahrnuly chyby ověřování:

public HttpResponseMessage PostProduct(Product item)
{
    if (!ModelState.IsValid)
    {
        return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
    }

    // Implementation not shown...
}

Tento příklad může vrátit následující odpověď:

HTTP/1.1 400 Bad Request
Content-Type: application/json; charset=utf-8
Content-Length: 320

{
  "Message": "The request is invalid.",
  "ModelState": {
    "item": [
      "Required property 'Name' not found in JSON. Path '', line 1, position 14."
    ],
    "item.Name": [
      "The Name field is required."
    ],
    "item.Price": [
      "The field Price must be between 0 and 999."
    ]
  }
}

Další informace o ověřování modelu najdete v tématu Ověření modelu ve webovém rozhraní API ASP.NET.

Použití chyby HttpError s exception httpResponseException

Předchozí příklady vrátí zprávu HttpResponseMessage z akce kontroleru, ale můžete také použít HttpResponseException k vrácení Chyby Http. To vám umožní vrátit model silného typu v normálním případě úspěchu a přesto vrátit chybu HttpError , pokud dojde k chybě:

public Product GetProduct(int id)
{
    Product item = repository.Get(id);
    if (item == null)
    {
        var message = string.Format("Product with id = {0} not found", id);
        throw new HttpResponseException(
            Request.CreateErrorResponse(HttpStatusCode.NotFound, message));
    }
    else
    {
        return item;
    }
}