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