Delen via


Afhandeling van uitzonderingen in ASP.NET Web-API

In dit artikel worden fout- en uitzonderingsafhandeling in ASP.NET Web-API beschreven.

HttpResponseException

Wat gebeurt er als een web-API-controller een niet-onderschepde uitzondering genereert? Standaard worden de meeste uitzonderingen omgezet in een HTTP-antwoord met statuscode 500, interne serverfout.

Het type HttpResponseException is een speciaal geval. Deze uitzondering retourneert http-statuscode die u opgeeft in de uitzonderingsconstructor. De volgende methode retourneert bijvoorbeeld 404, Niet gevonden, als de id-parameter ongeldig is.

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

Voor meer controle over het antwoord kunt u ook het hele antwoordbericht samenstellen en opnemen met 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;
}

Uitzonderingsfilters

U kunt aanpassen hoe web-API uitzonderingen verwerkt door een uitzonderingsfilter te schrijven. Er wordt een uitzonderingsfilter uitgevoerd wanneer een controllermethode een niet-verwerkte uitzondering genereert die geenHttpResponseException-uitzondering is. Het type HttpResponseException is een speciaal geval, omdat het speciaal is ontworpen voor het retourneren van een HTTP-antwoord.

Uitzonderingsfilters implementeren de interface System.Web.Http.Filters.IExceptionFilter . De eenvoudigste manier om een uitzonderingsfilter te schrijven is afgeleid van de klasse System.Web.Http.Filters.ExceptionFilterAttribute en de OnException-methode overschrijven.

Opmerking

Uitzonderingsfilters in ASP.NET Web-API zijn vergelijkbaar met filters in ASP.NET MVC. Ze worden echter afzonderlijk gedeclareerd in een afzonderlijke naamruimte en functie. Met name de HandleErrorAttribute-klasse die wordt gebruikt in MVC verwerkt geen uitzonderingen die worden gegenereerd door web-API-controllers.

Hier volgt een filter waarmee NotImplementedException-uitzonderingen worden geconverteerd naar HTTP-statuscode 501, Niet geïmplementeerd:

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

De eigenschap Response van het object HttpActionExecutedContext bevat het HTTP-antwoordbericht dat naar de client wordt verzonden.

Uitzonderingsfilters registreren

Er zijn verschillende manieren om een web-API-uitzonderingsfilter te registreren:

  • Per actie
  • Per controller
  • Wereldwijd

Als u het filter wilt toepassen op een specifieke actie, voegt u het filter toe als een kenmerk aan de actie:

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

Als u het filter wilt toepassen op alle acties op een controller, voegt u het filter toe als een kenmerk aan de controllerklasse:

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

Als u het filter globaal wilt toepassen op alle web-API-controllers, voegt u een exemplaar van het filter toe aan de verzameling GlobalConfiguration.Configuration.Filters . Uitzonderingsfilters in deze verzameling zijn van toepassing op een web-API-controlleractie.

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

Als u de projectsjabloon 'ASP.NET MVC 4-webtoepassing' gebruikt om uw project te maken, plaatst u de web-API-configuratiecode in de WebApiConfig klasse, die zich in de map App_Start bevindt:

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

        // Other configuration code...
    }
}

HttpError

Het HttpError-object biedt een consistente manier om foutinformatie in de hoofdtekst van het antwoord te retourneren. In het volgende voorbeeld ziet u hoe u HTTP-statuscode 404 (Niet gevonden) retourneert met een HttpError in de hoofdtekst van het antwoord.

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 is een extensiemethode die is gedefinieerd in de klasse System.Net.Http.HttpRequestMessageExtensions . Intern maakt CreateErrorResponse een HttpError-exemplaar en maakt vervolgens een HttpResponseMessage die de HttpError bevat.

Als de methode in dit voorbeeld is geslaagd, wordt het product geretourneerd in het HTTP-antwoord. Maar als het aangevraagde product niet wordt gevonden, bevat het HTTP-antwoord een HttpError in de aanvraagbody. Het antwoord kan er als volgt uitzien:

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

U ziet dat httpError in dit voorbeeld is geserialiseerd naar JSON. Een voordeel van het gebruik van HttpError is dat het hetzelfde proces voor inhoudsonderhandeling en serialisatie doorloopt als elk ander sterk getypeerd model.

HttpError- en modelvalidatie

Voor modelvalidatie kunt u de modelstatus doorgeven aan CreateErrorResponse om de validatiefouten in het antwoord op te nemen:

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

    // Implementation not shown...
}

In dit voorbeeld kan het volgende antwoord worden geretourneerd:

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

Zie Modelvalidatie in ASP.NET Web-API voor meer informatie over modelvalidatie.

HttpError gebruiken met HttpResponseException

De vorige voorbeelden retourneren een HttpResponseMessage-bericht van de controlleractie, maar u kunt ook HttpResponseException gebruiken om een HttpError te retourneren. Hiermee kunt u een sterk getypeerd model retourneren in het normale successcenario, terwijl nog steeds HttpError wordt geretourneerd als er een fout is.

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