Backend/e-suite.API/eSuite.API/Middleware/ExceptionCapture.cs
2026-01-20 21:50:10 +00:00

171 lines
5.3 KiB
C#

using System.ComponentModel.DataAnnotations;
using e_suite.API.Common;
using e_suite.API.Common.exceptions;
using e_suite.Database.Core.Extensions.Exceptions;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
namespace eSuite.API.Middleware;
/// <summary>
/// Exception capture middleware
/// </summary>
public class ExceptionCapture
{
private readonly RequestDelegate _next;
private readonly IExceptionLogManager _exceptionLogManager;
/// <summary>
/// Default constructor
/// </summary>
/// <param name="next"></param>
/// <param name="exceptionLogManager"></param>
public ExceptionCapture(RequestDelegate next, IExceptionLogManager exceptionLogManager)
{
_next = next;
_exceptionLogManager = exceptionLogManager;
}
/// <summary>
/// Called to wrap the controller method with general graceful error handling
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next.Invoke(context);
}
catch (GuidMismatchException ex)
{
await BadRequestResponse(context, ex);
}
catch (NotFoundException ex)
{
await NotFoundResponse(context, ex);
}
catch (ExistsException ex)
{
await BadRequestResponse(context, ex);
}
catch (InvalidOperationException ex)
{
await BadRequestResponse(context, ex);
}
catch( ValidationException ex)
{
await BadRequestResponse(context, ex);
}
catch (ArgumentException ex)
{
await BadRequestResponse(context, ex);
}
catch (InvalidReferenceObjectId ex)
{
await BadRequestResponse(context, ex);
}
catch (TokenInvalidException ex)
{
await BadRequestResponse(context, ex);
}
catch (InvalidEmailException ex)
{
await BadRequestResponse(context, ex);
}
catch (MinimumRangeException ex)
{
await BadRequestResponse(context, ex);
}
catch (MaximumRangeException ex)
{
await BadRequestResponse(context, ex);
}
catch (OperationCanceledException ex)
{
await BadRequestResponse(context, ex, "Request cancelled");
}
catch (Exception ex)
{
var supportingData = new
{
User = context.User.Identity != null ? context.User.Identity.Name : string.Empty,
context.Request.Query,
context.Request.Method,
context.Request.Path,
context.Request.Headers,
context.Request.Cookies,
context.Request.QueryString,
context.Items
}.ToJson();
var exceptionId = await _exceptionLogManager.LogException(ex, "e-suite API", supportingData, CancellationToken.None);
await InternalServerErrorResponse(context, ex, exceptionId);
}
}
private static async Task BadRequestResponse(HttpContext context, Exception ex, string title = "Bad request")
{
var problemDetails = new ProblemDetails
{
Title = title,
Detail = ex.Message
};
context.Response.StatusCode = StatusCodes.Status400BadRequest;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(problemDetails.ToJson());
}
private static async Task NotFoundResponse(HttpContext context, Exception ex, string title = "Not found")
{
var problemDetails = new ProblemDetails
{
Title = title,
Detail = ex.Message
};
context.Response.StatusCode = StatusCodes.Status404NotFound;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(problemDetails.ToJson());
}
private static async Task InternalServerErrorResponse(HttpContext context, Exception ex, long exceptionId, string title = "Internal Server Error")
{
var problemDetails = new ProblemDetails
{
Title = title,
Detail = ex.Message,
Instance = exceptionId.ToString()
};
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
context.Response.ContentType = "application/json";
await context.Response.WriteAsync(problemDetails.ToJson());
}
}
/// <summary>
///
/// </summary>
public static class ObjectExtensions
{
/// <summary>
/// Serialize the current object to Json
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string ToJson(this object value)
{
var options = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
NullValueHandling = NullValueHandling.Include
};
return JsonConvert.SerializeObject(value, options);
}
}