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#
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
|
|
}
|
|
}
|
|
} |