93 lines
3.9 KiB
C#
93 lines
3.9 KiB
C#
using FluentValidation;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.Extensions.Logging;
|
|
using Mirea.Api.DataAccess.Application.Common.Exceptions;
|
|
using Mirea.Api.Endpoint.Common.Exceptions;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Security;
|
|
using System.Text.Json;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Mirea.Api.Endpoint.Configuration.Core.Middleware;
|
|
|
|
public class CustomExceptionHandlerMiddleware(RequestDelegate next, ILogger<CustomExceptionHandlerMiddleware> logger)
|
|
{
|
|
public async Task InvokeAsync(HttpContext context)
|
|
{
|
|
try
|
|
{
|
|
await next(context);
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
await HandleExceptionAsync(context, exception);
|
|
}
|
|
}
|
|
|
|
private Task HandleExceptionAsync(HttpContext context, Exception exception)
|
|
{
|
|
var traceId = Activity.Current?.Id ?? context.TraceIdentifier;
|
|
|
|
var problemDetails = new ProblemDetails
|
|
{
|
|
Type = "https://tools.ietf.org/html/rfc9110#section-15.6.1",
|
|
Title = "An unexpected error occurred.",
|
|
Status = StatusCodes.Status500InternalServerError,
|
|
Detail = "Please provide this traceId to the administrator for further investigation.",
|
|
Extensions = new Dictionary<string, object?>()
|
|
{
|
|
{ "traceId", traceId }
|
|
}
|
|
};
|
|
|
|
switch (exception)
|
|
{
|
|
case ValidationException validationException:
|
|
problemDetails.Status = StatusCodes.Status400BadRequest;
|
|
problemDetails.Type = "https://tools.ietf.org/html/rfc9110#section-15.5.1";
|
|
problemDetails.Title = "Validation errors occurred.";
|
|
problemDetails.Extensions = new Dictionary<string, object?>
|
|
{
|
|
{ "errors", validationException.Errors.Select(e => e.ErrorMessage).ToArray() },
|
|
{ "traceId", traceId }
|
|
};
|
|
break;
|
|
case NotFoundException:
|
|
problemDetails.Status = StatusCodes.Status404NotFound;
|
|
problemDetails.Type = "https://tools.ietf.org/html/rfc9110#section-15.5.4";
|
|
problemDetails.Title = "Resource not found.";
|
|
break;
|
|
case ControllerArgumentException:
|
|
problemDetails.Status = StatusCodes.Status400BadRequest;
|
|
problemDetails.Type = "https://tools.ietf.org/html/rfc9110#section-15.5.1";
|
|
problemDetails.Title = "Invalid arguments provided.";
|
|
problemDetails.Detail = exception.Message;
|
|
break;
|
|
case SecurityException:
|
|
problemDetails.Status = StatusCodes.Status401Unauthorized;
|
|
problemDetails.Type = "https://tools.ietf.org/html/rfc9110#section-15.5.2";
|
|
problemDetails.Title = "Unauthorized access.";
|
|
break;
|
|
case ServerUnavailableException unavailableException:
|
|
problemDetails.Status = StatusCodes.Status503ServiceUnavailable;
|
|
problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc9110#section-15.6.4";
|
|
problemDetails.Title = "Server unavailable.";
|
|
problemDetails.Detail = unavailableException.Message;
|
|
if (unavailableException.AddRetryAfter)
|
|
context.Response.Headers.RetryAfter = "600";
|
|
break;
|
|
}
|
|
|
|
if (problemDetails.Status == StatusCodes.Status500InternalServerError)
|
|
logger.LogError(exception, "Internal server error when processing the request");
|
|
|
|
context.Response.ContentType = "application/json";
|
|
context.Response.StatusCode = problemDetails.Status.Value;
|
|
|
|
return context.Response.WriteAsync(JsonSerializer.Serialize(problemDetails));
|
|
}
|
|
} |