Files
tiku-backend.net/Tiku.Api/Middleware/ExceptionHandlingMiddleware.cs

68 lines
2.4 KiB
C#

using Microsoft.AspNetCore.Mvc;
namespace Tiku.Api.Middleware;
internal sealed class ExceptionHandlingMiddleware(
RequestDelegate next,
ILogger<ExceptionHandlingMiddleware> logger,
IHostEnvironment environment,
IEnumerable<IExceptionProblemDetailsMapper> mappers)
{
private readonly IReadOnlyCollection<IExceptionProblemDetailsMapper> problemDetailsMappers = mappers.ToArray();
public async Task InvokeAsync(HttpContext context)
{
try
{
await next(context);
}
catch (Exception exception)
{
var mappings = problemDetailsMappers
.Select(mapper => mapper.TryMap(exception, out var mapping) ? mapping : null)
.Where(mapping => mapping is not null)
.Cast<ExceptionProblemDetailsMapping>()
.ToArray();
if (mappings.Length == 1)
{
await WriteProblemAsync(context, mappings[0]);
return;
}
if (mappings.Length > 1)
logger.LogCritical(exception, "Multiple ProblemDetails mappers matched {ExceptionType}",
exception.GetType().FullName);
else
logger.LogError(exception, "Unhandled API exception");
var problem = new ProblemDetails
{
Title = "An unexpected error occurred.",
Status = StatusCodes.Status500InternalServerError,
Detail = environment.IsDevelopment() ? exception.Message : null,
Instance = context.Request.Path
};
problem.Extensions["traceId"] = context.TraceIdentifier;
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
await context.Response.WriteAsJsonAsync(problem);
}
}
private static async Task WriteProblemAsync(
HttpContext context,
ExceptionProblemDetailsMapping mapping)
{
var problem = new ProblemDetails
{
Title = mapping.Title,
Status = mapping.Status,
Instance = context.Request.Path
};
problem.Extensions["code"] = mapping.Code;
problem.Extensions["traceId"] = context.TraceIdentifier;
foreach (var extension in mapping.Extensions) problem.Extensions[extension.Key] = extension.Value;
context.Response.StatusCode = mapping.Status;
await context.Response.WriteAsJsonAsync(problem);
}
}