Compartir a través de


Control de errores en las API de ASP.NET Core

Nota:

Esta no es la versión más reciente de este artículo. Para la versión actual, consulte la versión de .NET 10 de este artículo.

Advertencia

Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulte la política de soporte de .NET y .NET Core. Para la versión actual, consulte la versión de .NET 9 de este artículo.

En este artículo se describe cómo controlar los errores en las API de ASP.NET Core. Se ha seleccionado la documentación de las API mínimas. Para ver la documentación de las API basadas en controladores, seleccione la pestaña Controladores. Para obtener instrucciones sobre Blazor el control de errores, consulte Control de errores en ASP.NET Aplicaciones principalesBlazor.

Página de excepciones de desarrollador

En la página Excepciones del desarrollador se muestra información detallada sobre las excepciones de solicitud no controladas. DeveloperExceptionPageMiddleware Usa para capturar excepciones sincrónicas y asincrónicas de la canalización HTTP y para generar respuestas de error. La página de excepciones de desarrollador se ejecuta al principio de la canalización de middleware, de modo que pueda detectar excepciones no controladas producidas en el middleware siguiente.

ASP.NET aplicaciones principales habilitan la página de excepciones para desarrolladores de forma predeterminada cuando ambas:

Las aplicaciones creadas con plantillas anteriores, es decir, mediante WebHost.CreateDefaultBuilder, pueden habilitar la página de excepciones del desarrollador llamando a app.UseDeveloperExceptionPage.

Advertencia

No habilite la página excepción del desarrollador a menos que la aplicación se ejecute en el entorno de desarrollo. No comparta información detallada de excepciones públicamente cuando la aplicación se ejecute en producción. Para obtener más información sobre la configuración de entornos, consulte entornos de ejecución de ASP.NET Core.

La página Excepción del desarrollador puede incluir la siguiente información sobre la excepción y la solicitud:

  • Seguimiento de pila
  • Parámetros de cadena de consulta, si los hay
  • Cookies, si las hay
  • Headers
  • Metadatos del punto de conexión, si los hay

No se garantiza que la página excepción del desarrollador proporcione ninguna información. Use el registro para obtener información de error completa.

En la imagen siguiente se muestra una página de excepción de desarrollador de ejemplo con animación para mostrar las pestañas y la información mostrada:

Página de excepciones del desarrollador animada para mostrar cada pestaña seleccionada.

En respuesta a una solicitud con un Accept: text/plain encabezado, la página excepción del desarrollador devuelve texto sin formato en lugar de HTML. Por ejemplo:

Status: 500 Internal Server Error
Time: 9.39 msSize: 480 bytes
FormattedRawHeadersRequest
Body
text/plain; charset=utf-8, 480 bytes
System.InvalidOperationException: Sample Exception
   at WebApplicationMinimal.Program.<>c.<Main>b__0_0() in C:\Source\WebApplicationMinimal\Program.cs:line 12
   at lambda_method1(Closure, Object, HttpContext)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

HEADERS
=======
Accept: text/plain
Host: localhost:7267
traceparent: 00-0eab195ea19d07b90a46cd7d6bf2f

Para ver la página Excepción de desarrollador en una API mínima:

En esta sección se hace referencia a la siguiente aplicación de ejemplo para mostrar formas de controlar excepciones en una API mínima. Produce una excepción cuando se solicita el punto de conexión /exception :

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/exception", () => 
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

Controlador de excepciones

En entornos que no son de desarrollo, use el middleware del controlador de excepciones para generar una carga de error.

Para configurar , Exception Handler Middlewarellame a UseExceptionHandler. Por ejemplo, el código siguiente cambia la aplicación para responder con una carga compatible con RFC 7807 al cliente. Para obtener más información, consulte la sección Detalles del problema más adelante en este artículo.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp 
    => exceptionHandlerApp.Run(async context 
        => await Results.Problem()
                     .ExecuteAsync(context)));

app.MapGet("/exception", () => 
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

Respuestas de error de cliente y servidor

Tenga en cuenta la siguiente aplicación de API mínima.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)));

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

El /users punto de conexión genera 200 OK una json representación de User cuando id es mayor que 0, de lo contrario, un 400 BAD REQUEST código de estado sin un cuerpo de respuesta. Para obtener más información sobre cómo crear una respuesta, consulte Creación de respuestas en aplicaciones de API mínimas.

Status Code Pages middleware se puede configurar para generar un contenido de cuerpo común, cuando está vacío, para todas las respuestas de cliente HTTP () o servidor (400-499500 -599). El middleware se configura llamando al método de extensión UseStatusCodePages .

Por ejemplo, en el ejemplo siguiente se cambia la aplicación para responder con una carga compatible con RFC 7807 al cliente para todas las respuestas de cliente y servidor, incluidos los errores de enrutamiento (por ejemplo, 404 NOT FOUND). Para obtener más información, consulte la sección Detalles del problema .

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseStatusCodePages(async statusCodeContext 
    => await Results.Problem(statusCode: statusCodeContext.HttpContext.Response.StatusCode)
                 .ExecuteAsync(statusCodeContext.HttpContext));

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Detalles del problema

Los detalles del problema no son el único formato de respuesta para describir un error de API HTTP; sin embargo, normalmente se usan para notificar errores para las API HTTP.

El servicio de detalles del problema implementa la interfaz , que admite la IProblemDetailsService creación de detalles del problema en ASP.NET Core. El AddProblemDetails(IServiceCollection) método de extensión en IServiceCollection registra la implementación predeterminada IProblemDetailsService .

En ASP.NET aplicaciones core, el siguiente middleware genera respuestas HTTP de detalles del problema cuando AddProblemDetails se llama a , excepto cuando el Accept encabezado HTTP de solicitud no incluye uno de los tipos de contenido admitidos por el registrado IProblemDetailsWriter (valor predeterminado: application/json):

Las aplicaciones de API mínimas se pueden configurar para generar respuesta de detalles del problema para todas las respuestas de error de servidor y cliente HTTP que aún no tienen contenido del cuerpo mediante el método de AddProblemDetails extensión.

El código siguiente configura la aplicación para generar detalles del problema:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler();
app.UseStatusCodePages();

app.MapGet("/users/{id:int}", (int id) 
    => id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)));

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Para obtener más información sobre el uso AddProblemDetailsde , vea Detalles del problema.

Reserva de IProblemDetailsService

En el código siguiente, httpContext.Response.WriteAsync("Fallback: An error occurred.") devuelve un error si la IProblemDetailsService implementación no puede generar un ProblemDetails:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseExceptionHandler(exceptionHandlerApp =>
{
    exceptionHandlerApp.Run(async httpContext =>
    {
        var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
        if (pds == null
            || !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
        {
            // Fallback behavior
            await httpContext.Response.WriteAsync("Fallback: An error occurred.");
        }
    });
});

app.MapGet("/exception", () =>
{
    throw new InvalidOperationException("Sample Exception");
});

app.MapGet("/", () => "Test by calling /exception");

app.Run();

El código anterior:

El ejemplo siguiente es similar al anterior, excepto que llama a Status Code Pages middleware.

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddProblemDetails();

var app = builder.Build();

app.UseStatusCodePages(statusCodeHandlerApp =>
{
    statusCodeHandlerApp.Run(async httpContext =>
    {
        var pds = httpContext.RequestServices.GetService<IProblemDetailsService>();
        if (pds == null
            || !await pds.TryWriteAsync(new() { HttpContext = httpContext }))
        {
            // Fallback behavior
            await httpContext.Response.WriteAsync("Fallback: An error occurred.");
        }
    });
});

app.MapGet("/users/{id:int}", (int id) =>
{
    return id <= 0 ? Results.BadRequest() : Results.Ok(new User(id));
});

app.MapGet("/", () => "Test by calling /users/{id:int}");

app.Run();

public record User(int Id);

Características adicionales de control de errores

Migración de controladores a API mínimas

Si va a migrar de api basadas en controlador a API mínimas:

  1. Reemplazar filtros de acción por filtros de punto de conexión o middleware
  2. Reemplazo de la validación del modelo por validación manual o enlace personalizado
  3. Reemplazar filtros de excepción por middleware de control de excepciones
  4. Configuración de los detalles del problema mediante AddProblemDetails() para respuestas de error coherentes

Cuándo usar el control de errores basado en el controlador

Considere la posibilidad de usar las API basadas en controlador si necesita:

  • Escenarios de validación de modelos complejos
  • Control centralizado de excepciones en varios controladores
  • Control específico sobre el formato de respuesta de error
  • Integración con características de MVC, como filtros y convenciones

Para obtener información detallada sobre el control de errores basado en el controlador, incluidos los errores de validación, la personalización de detalles del problema y los filtros de excepciones, consulte las secciones controladores .

Recursos adicionales