Control de errores en aplicaciones de API mínimas
Nota:
Esta no es la versión más reciente de este artículo. Para la versión actual, consulta la versión .NET 8 de este artículo.
Advertencia
Esta versión de ASP.NET Core ya no se admite. Para obtener más información, consulta la Directiva de soporte técnico de .NET y .NET Core. Para la versión actual, consulta la versión .NET 8 de este artículo.
Importante
Esta información hace referencia a un producto en versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.
Para la versión actual, consulte la versión .NET 8 de este artículo.
Con contribuciones de David Acker
En este artículo se describe cómo controlar los errores en aplicaciones de API mínimas. Para obtener información sobre el control de errores en las API basadas en controladores, consulte Controlar errores en ASP.NET Core y Controlar errores en las API web basadas en controladores de ASP.NET Core.
Excepciones
En una aplicación de API mínima, hay dos mecanismos centralizados integrados diferentes para controlar excepciones no controladas:
- Middleware de la página de excepciones para desarrolladores (solo para su uso en el entorno de desarrollo).
- Middleware del controlador de excepciones
Esta sección hace referencia a la siguiente aplicación de ejemplo para demostrar las formas de controlar las 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();
Página de excepciones para el desarrollador
En la Página de excepciones para el desarrollador se muestra información detallada sobre las excepciones de la solicitud no controladas. Usa DeveloperExceptionPageMiddleware para capturar excepciones sincrónicas y asincrónicas de la canalización HTTP y para generar respuestas de error. La página de excepciones del desarrollador se ejecuta al principio de la canalización del middleware, de modo que puede capturar las excepciones no controladas que se producen en el middleware que sigue.
De forma predeterminada, las aplicaciones de ASP.NET Core habilitan la página de excepciones del desarrollador cuando se cumplen las dos condiciones siguientes:
- Ejecutan en el entorno de desarrollo.
- La aplicación se creó con las plantillas actuales, es decir, con WebApplication.CreateBuilder.
Las aplicaciones creadas con plantillas anteriores, es decir, con WebHost.CreateDefaultBuilder, pueden habilitar la página de excepciones del desarrollador llamando a app.UseDeveloperExceptionPage
.
Advertencia
No habilite la página de excepciones para el desarrollador a menos que la aplicación se ejecute en el entorno de desarrollo. No comparta públicamente información detallada sobre las excepciones cuando la aplicación se ejecute en producción. Para más información sobre la configuración de los entornos, consulte Uso de varios entornos en ASP.NET Core.
La página de excepciones para el desarrollador puede incluir la siguiente información sobre la excepción y la solicitud:
- Seguimiento de la pila
- Parámetros de cadena de consulta (si existen)
- Cookies, si existen
- encabezados
- Metadatos del punto de conexión, si los hay
No se garantiza que la página de excepciones del desarrollador proporcione alguna información. Use el registro obtener información completa sobre el error.
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:
En respuesta a una solicitud con un encabezado Accept: text/plain
, la página de excepciones 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 de excepciones del desarrollador:
- Ejecute la aplicación de ejemplo en Entorno de desarrollo.
- Vaya al punto de conexión de
/exception
.
Controlador de excepciones
En entornos que no son de desarrollo, use el middleware de control de excepciones para producir una carga de error. Para configurar Exception Handler Middleware
, llame a UseExceptionHandler.
Por ejemplo, el código siguiente cambia la aplicación para responder con una carga compatible con RFC 7807 al cliente. Para 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 punto de conexión /users
genera 200 OK
con una representación json
de User
cuando id
es mayor que 0
, de lo contrario, un código de estado 400 BAD REQUEST
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 (400
-499
) o servidor (500
-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 que responda 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 más información, consulte la sección de 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 la API HTTP; sin embargo, se usan normalmente para notificar errores para las API HTTP.
El servicio de detalles del problema implementa la interfaz IProblemDetailsService, que admite la creación de detalles del problema en ASP.NET Core. El método de extensión AddProblemDetails(IServiceCollection) de IServiceCollection registra la implementación IProblemDetailsService
predeterminada.
En aplicaciones de ASP.NET Core, el middleware siguiente genera respuestas HTTP de detalles del problema cuando se llama a AddProblemDetails
, excepto cuando el encabezado HTTP de solicitud Accept
no incluye uno de los tipos de contenido admitidos por el IProblemDetailsWriter registrado (valor predeterminado: application/json
):
- ExceptionHandlerMiddleware: genera una respuesta de detalles del problema cuando no se define un controlador personalizado.
- StatusCodePagesMiddleware: genera una respuesta de detalles del problema de forma predeterminada.
- DeveloperExceptionPageMiddleware: genera una respuesta de detalles del problema en el desarrollo cuando el encabezado HTTP de solicitud
Accept
no incluyetext/html
.
Las aplicaciones de API mínimas se pueden configurar para generar respuestas 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 extensión AddProblemDetails
.
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 más información sobre el uso de AddProblemDetails
, consulte Detalles del problema.
Reserva de IProblemDetailsService
En el código siguiente, httpContext.Response.WriteAsync("Fallback: An error occurred.")
devuelve un error si la implementación de IProblemDetailsService no puede generar 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:
- Escribe un mensaje de error con el código de reserva si
problemDetailsService
no puede escribir .ProblemDetails
Por ejemplo, un punto de conexión donde el encabezado de solicitud Accept especifica un tipo de soporte físico queDefaulProblemDetailsWriter
no admite. - Usa el middleware del controlador de excepciones.
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);
En este artículo se describe cómo controlar los errores en aplicaciones de API mínimas.
Excepciones
En una aplicación de API mínima, hay dos mecanismos centralizados integrados diferentes para controlar excepciones no controladas:
- Middleware de la página de excepciones para desarrolladores (solo para su uso en el entorno de desarrollo).
- Middleware del controlador de excepciones
En esta sección se hace referencia a la siguiente aplicación de API mínima para mostrar formas de controlar las excepciones. Produce una excepción cuando se solicita el punto de conexión /exception
:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.Map("/exception", ()
=> { throw new InvalidOperationException("Sample Exception"); });
app.Run();
Página de excepciones para el desarrollador
La página de excepciones para el desarrollador muestra seguimientos de pila detallados de los errores del servidor. Usa DeveloperExceptionPageMiddleware para capturar excepciones sincrónicas y asincrónicas de la canalización HTTP y para generar respuestas de error.
De forma predeterminada, las aplicaciones de ASP.NET Core habilitan la página de excepciones del desarrollador cuando se cumplen las dos condiciones siguientes:
- Ejecutan en el entorno de desarrollo.
- La aplicación usa WebApplication.CreateBuilder.
Para obtener más información sobre cómo configurar middleware, consulte Middleware en aplicaciones de API mínimas.
Con la aplicación de API mínima anterior, cuando Developer Exception Page
detecta una excepción no controlada, genera una respuesta de texto sin formato predeterminada similar al ejemplo siguiente:
HTTP/1.1 500 Internal Server Error
Content-Type: text/plain; charset=utf-8
Date: Thu, 27 Oct 2022 18:00:59 GMT
Server: Kestrel
Transfer-Encoding: chunked
System.InvalidOperationException: Sample Exception
at Program.<>c.<<Main>$>b__0_1() in ....:line 17
at lambda_method2(Closure, Object, HttpContext)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Connection: keep-alive
Host: localhost:5239
Accept-Encoding: gzip, deflate, br
Advertencia
No habilite la página de excepciones para el desarrollador a menos que la aplicación se ejecute en el entorno de desarrollo. No comparta públicamente información detallada sobre las excepciones cuando la aplicación se ejecute en producción. Para más información sobre la configuración de los entornos, consulte Uso de varios entornos en ASP.NET Core.
Controlador de excepciones
En entornos que no son de desarrollo, use el middleware de control de excepciones para producir una carga de error. Para configurar Exception Handler Middleware
, llame a UseExceptionHandler.
Por ejemplo, el código siguiente cambia la aplicación para responder con una carga compatible con RFC 7807 al cliente. Para más información, consulte la sección de detalles del problema.
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseExceptionHandler(exceptionHandlerApp
=> exceptionHandlerApp.Run(async context
=> await Results.Problem()
.ExecuteAsync(context)));
app.Map("/exception", ()
=> { throw new InvalidOperationException("Sample 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.Map("/users/{id:int}", (int id)
=> id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );
app.Run();
public record User(int Id);
El punto de conexión /users
genera 200 OK
con una representación json
de User
cuando id
es mayor que 0
, de lo contrario, un código de estado 400 BAD REQUEST
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 (400
-499
) o servidor (500
-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 que responda 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 más información, consulte la sección de 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.Map("/users/{id:int}", (int id)
=> id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );
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 la API HTTP; sin embargo, se usan normalmente para notificar errores para las API HTTP.
El servicio de detalles del problema implementa la interfaz IProblemDetailsService, que admite la creación de detalles del problema en ASP.NET Core. El método de extensión AddProblemDetails(IServiceCollection) de IServiceCollection registra la implementación IProblemDetailsService
predeterminada.
En aplicaciones de ASP.NET Core, el middleware siguiente genera respuestas HTTP de detalles del problema cuando se llama a AddProblemDetails
, excepto cuando el encabezado HTTP de solicitud Accept
no incluye uno de los tipos de contenido admitidos por el IProblemDetailsWriter registrado (valor predeterminado: application/json
):
- ExceptionHandlerMiddleware: genera una respuesta de detalles del problema cuando no se define un controlador personalizado.
- StatusCodePagesMiddleware: genera una respuesta de detalles del problema de forma predeterminada.
- DeveloperExceptionPageMiddleware: genera una respuesta de detalles del problema en el desarrollo cuando el encabezado HTTP de solicitud
Accept
no incluyetext/html
.
Las aplicaciones de API mínimas se pueden configurar para generar respuestas 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 extensión AddProblemDetails
.
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.Map("/users/{id:int}", (int id)
=> id <= 0 ? Results.BadRequest() : Results.Ok(new User(id)) );
app.Map("/exception", ()
=> { throw new InvalidOperationException("Sample Exception"); });
app.Run();
Para más información sobre el uso de AddProblemDetails
, consulte Detalles del problema.