Ausnahmebehandlung in ASP.NET-Web-API
In diesem Artikel wird die Fehler- und Ausnahmebehandlung in ASP.NET-Web-API beschrieben.
HttpResponseException
Was geschieht, wenn ein Web-API-Controller eine uncauaught-Ausnahme auslöst? Standardmäßig werden die meisten Ausnahmen in eine HTTP-Antwort mit status Code 500( Interner Serverfehler) übersetzt.
Der HttpResponseException-Typ ist ein Sonderfall. Diese Ausnahme gibt alle HTTP-status Code zurück, den Sie im Ausnahmekonstruktor angeben. Die folgende Methode gibt z. B. 404, Not Found, zurück, wenn der id-Parameter ungültig ist.
public Product GetProduct(int id)
{
Product item = repository.Get(id);
if (item == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return item;
}
Um mehr Kontrolle über die Antwort zu erhalten, können Sie auch die gesamte Antwortnachricht erstellen und in die HttpResponseException einschließen:
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;
}
Ausnahmefilter
Sie können anpassen, wie die Web-API Ausnahmen behandelt, indem Sie einen Ausnahmefilter schreiben. Ein Ausnahmefilter wird ausgeführt, wenn eine Controllermethode eine nicht behandelte Ausnahme auslöst, die keineHttpResponseException-Ausnahme ist. Der HttpResponseException-Typ ist ein Sonderfall, da er speziell für die Rückgabe einer HTTP-Antwort entwickelt wurde.
Ausnahmefilter implementieren die System.Web.Http.Filters.IExceptionFilter-Schnittstelle . Die einfachste Möglichkeit zum Schreiben eines Ausnahmefilters besteht darin, von der System.Web.Http.Filters.ExceptionFilterAttribute-Klasse abzuleiten und die OnException-Methode zu überschreiben.
Hinweis
Ausnahmefilter in ASP.NET-Web-API ähneln denen in ASP.NET MVC. Sie werden jedoch in einem separaten Namespace und einer separaten Funktion separat deklariert. Insbesondere behandelt die in MVC verwendete HandleErrorAttribute-Klasse keine Ausnahmen, die von Web-API-Controllern ausgelöst werden.
Hier ist ein Filter, der NotImplementedException-Ausnahmen in HTTP-status Code 501, Nicht implementiert konvertiert:
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);
}
}
}
}
Die Response-Eigenschaft des HttpActionExecutedContext-Objekts enthält die HTTP-Antwortnachricht, die an den Client gesendet wird.
Registrieren von Ausnahmefiltern
Es gibt mehrere Möglichkeiten zum Registrieren eines Web-API-Ausnahmefilters:
- Nach Aktion
- Nach Controller
- Global
Um den Filter auf eine bestimmte Aktion anzuwenden, fügen Sie den Filter der Aktion als Attribut hinzu:
public class ProductsController : ApiController
{
[NotImplExceptionFilter]
public Contact GetContact(int id)
{
throw new NotImplementedException("This method is not implemented");
}
}
Um den Filter auf alle Aktionen auf einem Controller anzuwenden, fügen Sie den Filter der Controllerklasse als Attribut hinzu:
[NotImplExceptionFilter]
public class ProductsController : ApiController
{
// ...
}
Um den Filter global auf alle Web-API-Controller anzuwenden, fügen Sie der GlobalConfiguration.Configuration.Filters-Auflistung eine instance des Filters hinzu. Ausnahmefilter in dieser Sammlung gelten für alle Web-API-Controlleraktionen.
GlobalConfiguration.Configuration.Filters.Add(
new ProductStore.NotImplExceptionFilterAttribute());
Wenn Sie zum Erstellen Ihres Projekts die Projektvorlage "ASP.NET MVC 4 Web Application" verwenden, platzieren Sie den Web-API-Konfigurationscode in der WebApiConfig
Klasse, die sich im Ordner App_Start befindet:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new ProductStore.NotImplExceptionFilterAttribute());
// Other configuration code...
}
}
HttpError
Das HttpError-Objekt bietet eine konsistente Möglichkeit, Fehlerinformationen im Antworttext zurückzugeben. Das folgende Beispiel zeigt, wie HTTP-status Code 404 (Nicht gefunden) mit einem HttpError im Antworttext zurückgegeben wird.
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 ist eine Erweiterungsmethode, die in der System.Net.Http.HttpRequestMessageExtensions-Klasse definiert ist. Intern erstellt CreateErrorResponse einen HttpError-instance und dann eine HttpResponseMessage, die den HttpError enthält.
Wenn die Methode in diesem Beispiel erfolgreich ist, wird das Produkt in der HTTP-Antwort zurückgegeben. Wenn das angeforderte Produkt jedoch nicht gefunden wird, enthält die HTTP-Antwort einen HttpError im Anforderungstext. Die Antwort kann wie folgt aussehen:
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"
}
Beachten Sie, dass der HttpError in diesem Beispiel in JSON serialisiert wurde. Ein Vorteil der Verwendung von HttpError besteht darin, dass es den gleichen Inhaltsverhandlungs- und Serialisierungsprozess durchläuft wie jedes andere stark typisierte Modell.
HttpError und Modellvalidierung
Für die Modellvalidierung können Sie den Modellzustand an CreateErrorResponse übergeben, um die Validierungsfehler in die Antwort einzuschließen:
public HttpResponseMessage PostProduct(Product item)
{
if (!ModelState.IsValid)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
// Implementation not shown...
}
In diesem Beispiel wird möglicherweise die folgende Antwort zurückgegeben:
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."
]
}
}
Weitere Informationen zur Modellvalidierung finden Sie unter Modellvalidierung in ASP.NET-Web-API.
Verwenden von HttpError mit HttpResponseException
In den vorherigen Beispielen wird eine HttpResponseMessage-Nachricht von der Controlleraktion zurückgegeben, Sie können aber auch HttpResponseException verwenden, um einen HttpError zurückzugeben. Auf diese Weise können Sie im normalen Erfolgsfall ein stark typisiertes Modell zurückgeben, während sie weiterhin HttpError zurückgeben, wenn ein Fehler vorliegt:
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;
}
}