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.
178 lines
6.0 KiB
C#
178 lines
6.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.Linq;
|
|
using System.Text.Json;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.Filters;
|
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
using Haoliang.Core.Services;
|
|
using Haoliang.Models.Common;
|
|
using DataAnnotationsValidationResult = System.ComponentModel.DataAnnotations.ValidationResult;
|
|
|
|
namespace Haoliang.Api.Filters
|
|
{
|
|
public class ValidationFilter : IActionFilter
|
|
{
|
|
private readonly ILoggingService _loggingService;
|
|
|
|
public ValidationFilter(ILoggingService loggingService)
|
|
{
|
|
_loggingService = loggingService;
|
|
}
|
|
|
|
public void OnActionExecuting(ActionExecutingContext context)
|
|
{
|
|
// Check if model state is valid
|
|
if (!context.ModelState.IsValid)
|
|
{
|
|
LogValidationErrors(context.ModelState);
|
|
context.Result = CreateValidationErrorResponse(context.ModelState);
|
|
}
|
|
}
|
|
|
|
public void OnActionExecuted(ActionExecutedContext context)
|
|
{
|
|
// No operation needed
|
|
}
|
|
|
|
private void LogValidationErrors(ModelStateDictionary modelState)
|
|
{
|
|
var errors = new Dictionary<string, List<string>>();
|
|
|
|
foreach (var keyModelStatePair in modelState)
|
|
{
|
|
var key = keyModelStatePair.Key;
|
|
var modelStateErrors = keyModelStatePair.Value.Errors;
|
|
|
|
if (modelStateErrors.Count > 0)
|
|
{
|
|
errors[key] = modelStateErrors.Select(error =>
|
|
string.IsNullOrEmpty(error.ErrorMessage) ? "Validation error occurred" : error.ErrorMessage
|
|
).ToList();
|
|
}
|
|
}
|
|
|
|
_loggingService.LogWarningAsync($"Model validation failed: {JsonSerializer.Serialize(errors)}").Wait();
|
|
}
|
|
|
|
private IActionResult 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 =>
|
|
string.IsNullOrEmpty(error.ErrorMessage) ? "Validation error occurred" : error.ErrorMessage
|
|
).ToArray();
|
|
|
|
if (errorsArray.Length > 0)
|
|
{
|
|
errors[key] = errorsArray;
|
|
}
|
|
}
|
|
|
|
var response = new ApiResponse<Dictionary<string, string[]>>
|
|
{
|
|
Success = false,
|
|
Message = "Validation failed",
|
|
ErrorCode = 400,
|
|
Data = errors,
|
|
Timestamp = DateTime.Now
|
|
};
|
|
|
|
return new BadRequestObjectResult(response);
|
|
}
|
|
}
|
|
|
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
|
public class ValidateModelAttribute : ActionFilterAttribute
|
|
{
|
|
public override 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 =>
|
|
string.IsNullOrEmpty(error.ErrorMessage) ? "Validation error occurred" : error.ErrorMessage
|
|
).ToArray();
|
|
|
|
if (errorsArray.Length > 0)
|
|
{
|
|
errors[key] = errorsArray;
|
|
}
|
|
}
|
|
|
|
var response = new ApiResponse<Dictionary<string, string[]>>
|
|
{
|
|
Success = false,
|
|
Message = "Validation failed",
|
|
ErrorCode = 400,
|
|
Data = errors,
|
|
Timestamp = DateTime.Now
|
|
};
|
|
|
|
context.Result = new BadRequestObjectResult(response);
|
|
}
|
|
|
|
base.OnActionExecuting(context);
|
|
}
|
|
}
|
|
|
|
public class ValidationHelper
|
|
{
|
|
public static (bool IsValid, List<string> Errors) ValidateModel(object model)
|
|
{
|
|
var validationContext = new ValidationContext(model);
|
|
var validationResults = new List<DataAnnotationsValidationResult>();
|
|
var isValid = Validator.TryValidateObject(model, validationContext, validationResults, true);
|
|
|
|
var errors = validationResults.Select(vr => vr.ErrorMessage).ToList();
|
|
|
|
return (isValid, errors);
|
|
}
|
|
|
|
public static (bool IsValid, List<string> Errors) ValidateDictionary(Dictionary<string, object> data, Dictionary<string, Type> expectedTypes)
|
|
{
|
|
var errors = new List<string>();
|
|
var isValid = true;
|
|
|
|
foreach (var kvp in expectedTypes)
|
|
{
|
|
if (!data.ContainsKey(kvp.Key))
|
|
{
|
|
errors.Add($"Missing required field: {kvp.Key}");
|
|
isValid = false;
|
|
continue;
|
|
}
|
|
|
|
var value = data[kvp.Key];
|
|
var expectedType = kvp.Value;
|
|
|
|
if (value == null)
|
|
{
|
|
if (expectedType == typeof(string))
|
|
{
|
|
errors.Add($"Field {kvp.Key} cannot be empty");
|
|
isValid = false;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (!expectedType.IsAssignableFrom(value.GetType()))
|
|
{
|
|
errors.Add($"Field {kvp.Key} must be of type {expectedType.Name}, got {value.GetType().Name}");
|
|
isValid = false;
|
|
}
|
|
}
|
|
|
|
return (isValid, errors);
|
|
}
|
|
}
|
|
} |