MireaBackend/Endpoint/Configuration/Core/Middleware/CustomExceptionHandlerMiddleware.cs

92 lines
3.7 KiB
C#
Raw Normal View History

using FluentValidation;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
2024-10-27 03:02:25 +03:00
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;
2024-10-31 04:07:35 +03:00
using System.Security;
using System.Text.Json;
using System.Threading.Tasks;
2024-10-07 02:25:36 +03:00
namespace Mirea.Api.Endpoint.Configuration.Core.Middleware;
2024-10-27 03:02:25 +03:00
public class CustomExceptionHandlerMiddleware(RequestDelegate next, ILogger<CustomExceptionHandlerMiddleware> logger)
{
2024-08-12 21:36:07 +03:00
public async Task InvokeAsync(HttpContext context)
{
try
{
await next(context);
}
catch (Exception exception)
{
await HandleExceptionAsync(context, exception);
}
}
2024-10-27 03:02:25 +03:00
private Task HandleExceptionAsync(HttpContext context, Exception exception)
{
var traceId = Activity.Current?.Id ?? context.TraceIdentifier;
var problemDetails = new ProblemDetails
{
2024-12-26 16:39:29 +03:00
Type = "https://tools.ietf.org/html/rfc9110#section-15.6.1",
Title = "An unexpected error occurred.",
Status = StatusCodes.Status500InternalServerError,
Detail = exception.Message,
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.";
break;
2024-10-31 04:07:35 +03:00
case SecurityException:
problemDetails.Status = StatusCodes.Status401Unauthorized;
problemDetails.Type = "https://tools.ietf.org/html/rfc9110#section-15.5.2";
problemDetails.Title = "Unauthorized access.";
2024-10-31 04:07:35 +03:00
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)
2024-10-27 04:36:20 +03:00
logger.LogError(exception, "Internal server error when processing the request");
2024-10-27 03:02:25 +03:00
context.Response.ContentType = "application/json";
context.Response.StatusCode = problemDetails.Status.Value;
return context.Response.WriteAsync(JsonSerializer.Serialize(problemDetails));
}
}