68 lines
2.4 KiB
C#
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);
|
|
}
|
|
}
|