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 interfejsie API sieci Web 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łą wiadomość odpowiedzi i dołączyć ją do wyjątku 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

Sposób obsługi wyjątków przez internetowy interfejs API można dostosować, pisząc filtr wyjątków. Filtr wyjątku jest wykonywany, kiedy 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 użycie klasy System.Web.Http.Filters.ExceptionFilterAttribute i zastąpienie metody OnException .

Uwaga / Notatka

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 działają niezależnie. W szczególności klasa HandleErrorAttribute używana w mvC nie obsługuje wyjątków zgłaszanych przez kontrolery internetowego interfejsu API.

Oto filtr, który konwertuje wyjątki NotImplementedException na kod stanu HTTP 501, Niezaimplementowane.

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 webowego interfejsu API:

  • Sortowane według akcji
  • Przez kontroler
  • 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 internetowego interfejsu API, 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 do utworzenia projektu używasz szablonu projektu "ASP.NET MVC 4 Web Application", umieść kod konfiguracji internetowego interfejsu API wewnątrz WebApiConfig klasy, który 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 funkcja CreateErrorResponse tworzy wystąpienie 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 HttpError jest to, że przechodzi on przez ten sam proces negocjacji zawartości i serializacji, co każdy inny silnie typizowany model.

HttpError i walidacja modelu

W przypadku walidacji 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...
}

Ten przykład może zwrócić następującą 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, zajrzyj do Walidacja modelu w ASP.NET Web API.

Używanie HttpError z 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;
    }
}