error handling

This commit is contained in:
José Henrique 2025-06-20 23:11:35 -03:00
parent 8159799c16
commit 7cf9380556

View File

@ -0,0 +1,104 @@
---
title: "Error Handling Dotnet"
date: 2024-06-20T20:00:06-03:00
draft: false
summary: "Because returning stack traces isn't secure."
---
The main idea behind having centralized error handling is that we can process any unhandled exception to:
* Return formatted responses without revealing any internal functionality
* Process issues so that they are properly logged on logs or other monitoring systems (like Sentry)
* Make sure all errors have the same external behavior
For that, we will use a new middleware class:
```csharp
public class ErrorResponse
{
public string Message { get; set; }
}
public class ErrorHandlerMiddleware {
private readonly RequestDelegate _next;
private readonly ILogger<ErrorHandlerMiddleware> _logger;
private readonly IHostEnvironment _env;
public ErrorHandlerMiddleware(RequestDelegate next, ILogger<ErrorHandlerMiddleware> logger, IHostEnvironment env){
_next = next;
_logger = logger;
_env = env;
}
public async Task Invoke(HttpContext httpContext)
{
// Attempts to execute the next action on the http chain
// If it fails, we log the exception and trigger the HandleErrorAsync method
try
{
await _next(httpContext);
}
catch(Exception ex)
{
_logger.LogError(ex, "An unhandled exception has occurred: {Message}", ex.Message);
await HandleErrorAsync(httpContext, ex);
}
}
private async Task HandleErrorAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int) HttpStatusCode.InternalServerError;
ErrorResponse errorResponse;
if (_env.IsDevelopment())
{
// In development, we want to see the full details for easier debugging.
errorResponse = new ErrorResponse
{
Message = exception.ToString()
};
}
else
{
// In production, we return a generic message to avoid leaking details.
errorResponse = new ErrorResponse
{
Message = "An internal server error occurred. Please try again later."
};
}
// We use the modern System.Text.Json for serialization via WriteAsJsonAsync
await context.Response.WriteAsJsonAsync(errorResponse);
}
}
```
We will also define a new Extension class to register this middleware:
```csharp
public static class ErrorHandlerExtensions
{
public static IApplicationBuilder UseErrorHandler(this IApplicationBuilder appBuilder)
{
return appBuilder.UseMiddleware<ErrorHandler>();
}
}
```
And then we just configure it on the `Configure()` method at the startup:
```csharp
public void Configure(IApplicationBuilder app)
{
app.UseErrorHandler();
}
```
Now, when there's an issue on the API execution, the API will return something like this:
```json
{
"Message": "Internal Server Error"
}
```
Sources:
* [https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/write?view=aspnetcore-8.0](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/write?view=aspnetcore-8.0)