Udostępnij za pośrednictwem


Obsługa wyjątków w internetowym interfejsie API ASP.NET

W tym artykule opisano obsługę błędów i wyjątków w internetowym interfejsie API ASP.NET.

HttpResponseException

Co się stanie, jeśli kontroler internetowego interfejsu API zgłosi nieuchwycony wyjątek? Domyślnie większość wyjątków jest tłumaczona na odpowiedź HTTP z kodem stanu 500 wewnętrzny błąd serwera.

Typ HttpResponseException jest specjalnym przypadkiem. Ten wyjątek zwraca dowolny kod stanu HTTP określony w konstruktorze wyjątku. Na przykład poniższa metoda zwraca wartość 404, Nie znaleziono, jeśli parametr id jest nieprawidłowy.

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

Aby uzyskać większą kontrolę nad odpowiedzią, możesz również skonstruować cały komunikat odpowiedzi i dołączyć go do błędu 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 wyjątków

Możesz dostosować sposób obsługi wyjątków przez internetowy interfejs API, pisząc filtr wyjątków. Filtr wyjątku jest wykonywany, gdy metoda kontrolera zgłasza nieobsługiwany wyjątek, który nie jest wyjątkiem HttpResponseException . Typ HttpResponseException jest specjalnym przypadkiem, ponieważ jest przeznaczony specjalnie do zwracania odpowiedzi HTTP.

Filtry wyjątków implementują interfejs System.Web.Http.Filters.IExceptionFilter . Najprostszym sposobem na napisanie filtru wyjątku jest utworzenie klasy System.Web.Http.Filters.ExceptionFilterAttribute i zastąpienie metody OnException .

Uwaga

Filtry wyjątków w internetowym interfejsie API ASP.NET są podobne do filtrów w ASP.NET MVC. Jednak są one deklarowane w oddzielnej przestrzeni nazw i funkcji oddzielnie. W szczególności klasa HandleErrorAttribute używana w mvC nie obsługuje wyjątków zgłaszanych przez kontrolery interfejsu API sieci Web.

Oto filtr, który konwertuje wyjątki NotImplementedException na kod stanu HTTP 501, Not Implementowane:

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);
            }
        }
    }
}

Właściwość Response obiektu HttpActionExecutedContext zawiera komunikat odpowiedzi HTTP, który zostanie wysłany do klienta.

Rejestrowanie filtrów wyjątków

Istnieje kilka sposobów rejestrowania filtru wyjątków internetowego interfejsu API:

  • Według akcji
  • Według kontrolera
  • Globalnie

Aby zastosować filtr do określonej akcji, dodaj filtr jako atrybut do akcji:

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

Aby zastosować filtr do wszystkich akcji na kontrolerze, dodaj filtr jako atrybut do klasy kontrolera:

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

Aby zastosować filtr globalnie do wszystkich kontrolerów interfejsu API sieci Web, dodaj wystąpienie filtru do kolekcji GlobalConfiguration.Configuration.Filters . Filtry wyjątków w tej kolekcji mają zastosowanie do dowolnej akcji kontrolera internetowego interfejsu API.

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

Jeśli używasz szablonu projektu "aplikacja internetowa ASP.NET MVC 4" do utworzenia projektu, umieść kod konfiguracji internetowego interfejsu API w WebApiConfig klasie , która znajduje się w folderze App_Start:

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

        // Other configuration code...
    }
}

HttpError

Obiekt HttpError zapewnia spójny sposób zwracania informacji o błędach w treści odpowiedzi. W poniższym przykładzie pokazano, jak zwrócić kod stanu HTTP 404 (Nie znaleziono) z błędem HttpError w treści odpowiedzi.

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 to metoda rozszerzenia zdefiniowana w klasie System.Net.Http.HttpRequestMessageExtensions . Wewnętrznie metoda CreateErrorResponse tworzy wystąpienie błędu HttpError , a następnie tworzy komunikat HttpResponseMessage zawierający błąd HttpError.

W tym przykładzie, jeśli metoda zakończy się pomyślnie, zwraca produkt w odpowiedzi HTTP. Jeśli jednak żądany produkt nie zostanie znaleziony, odpowiedź HTTP zawiera błąd HttpError w treści żądania. Odpowiedź może wyglądać następująco:

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

Zwróć uwagę, że błąd HttpError został serializowany do formatu JSON w tym przykładzie. Jedną z zalet korzystania z błędu HttpError jest to, że przechodzi on przez ten sam proces negocjowania zawartości i serializacji, co każdy inny silnie typizowane model.

HttpError i walidacja modelu

W przypadku weryfikacji modelu można przekazać stan modelu do metody CreateErrorResponse, aby uwzględnić błędy walidacji w odpowiedzi:

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

    // Implementation not shown...
}

W tym przykładzie może zostać zwrócona następująca odpowiedź:

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

Aby uzyskać więcej informacji na temat walidacji modelu, zobacz Walidacja modelu w ASP.NET internetowym interfejsie API.

Używanie błędu HttpError z błędem HttpResponseException

Poprzednie przykłady zwracają komunikat HttpResponseMessage z akcji kontrolera, ale można również użyć httpResponseException , aby zwrócić błąd HttpError. Umożliwia to zwrócenie silnie typizowanego modelu w normalnym przypadku powodzenia, a jednocześnie zwracanie błędu HttpError w przypadku wystąpienia błędu:

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