You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

175 lines
5.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Logging;
using Haoliang.Core.Services;
using Haoliang.Models.Common;
namespace Haoliang.Api.Filters
{
public class GlobalExceptionFilter : IExceptionFilter
{
private readonly ILogger<GlobalExceptionFilter> _logger;
private readonly ILoggingService _loggingService;
public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger, ILoggingService loggingService)
{
_logger = logger;
_loggingService = loggingService;
}
public void OnException(ExceptionContext context)
{
// Log the exception
_logger.LogError(context.Exception, "An unhandled exception occurred");
await _loggingService.LogErrorAsync($"Unhandled exception: {context.Exception.Message}", context.Exception);
// Handle specific exception types
if (context.Exception is ValidationException)
{
context.Result = CreateValidationResult(context.Exception as ValidationException);
context.ExceptionHandled = true;
return;
}
if (context.Exception is NotFoundException)
{
context.Result = new NotFoundObjectResult(CreateErrorResponse("Resource not found", 404));
context.ExceptionHandled = true;
return;
}
if (context.Exception is ForbiddenException)
{
context.Result = new ObjectResult(CreateErrorResponse("Access forbidden", 403))
{
StatusCode = 403
};
context.ExceptionHandled = true;
return;
}
if (context.Exception is BadRequestException)
{
context.Result = new BadRequestObjectResult(CreateErrorResponse("Bad request", 400));
context.ExceptionHandled = true;
return;
}
// Handle model state validation errors
if (!context.ModelState.IsValid)
{
context.Result = new BadRequestObjectResult(CreateValidationErrorResponse(context.ModelState));
context.ExceptionHandled = true;
return;
}
// Default handling for unhandled exceptions
context.Result = new ObjectResult(CreateErrorResponse("An unexpected error occurred", 500))
{
StatusCode = 500
};
context.ExceptionHandled = true;
}
private IActionResult CreateValidationResult(ValidationException validationException)
{
var response = new ApiResponse<Dictionary<string, string[]>>
{
Success = false,
Message = "Validation failed",
ErrorCode = 400,
Data = validationException?.Errors as Dictionary<string, string[]> ?? new Dictionary<string, string[]>(),
Timestamp = DateTime.Now
};
return new BadRequestObjectResult(response);
}
private object CreateErrorResponse(string message, int errorCode)
{
return new ApiResponse<object>
{
Success = false,
Message = message,
ErrorCode = errorCode,
Timestamp = DateTime.Now
};
}
private object CreateValidationErrorResponse(ModelStateDictionary modelState)
{
var errors = new Dictionary<string, string[]>();
foreach (var keyModelStatePair in modelState)
{
var key = keyModelStatePair.Key;
var errorsArray = keyModelStatePair.Value.Errors.Select(error => error.ErrorMessage).ToArray();
if (errorsArray.Length > 0)
{
errors[key] = errorsArray;
}
}
return new ApiResponse<Dictionary<string, string[]>>
{
Success = false,
Message = "Validation failed",
ErrorCode = 400,
Data = errors,
Timestamp = DateTime.Now
};
}
}
public class ModelStateValidationFilter : IActionFilter
{
private readonly ILogger<ModelStateValidationFilter> _logger;
public ModelStateValidationFilter(ILogger<ModelStateValidationFilter> logger)
{
_logger = logger;
}
public void OnActionExecuting(ActionExecutingContext context)
{
if (!context.ModelState.IsValid)
{
var errors = new Dictionary<string, string[]>();
foreach (var keyModelStatePair in context.ModelState)
{
var key = keyModelStatePair.Key;
var errorsArray = keyModelStatePair.Value.Errors.Select(error => error.ErrorMessage).ToArray();
if (errorsArray.Length > 0)
{
errors[key] = errorsArray;
}
}
_logger.LogWarning($"Model validation failed: {JsonSerializer.Serialize(errors)}");
context.Result = new BadRequestObjectResult(new ApiResponse<Dictionary<string, string[]>>
{
Success = false,
Message = "Validation failed",
ErrorCode = 400,
Data = errors,
Timestamp = DateTime.Now
});
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
// No operation needed
}
}
}