🏗 ساخت یکپارچهسازی FluentValidation
برای ادغام FluentValidation با Options Pattern، نیاز داریم یک پیادهسازی سفارشی از <IValidateOptions<T بسازیم:
using FluentValidation;
using Microsoft.Extensions.Options;
public class FluentValidateOptions<TOptions>
: IValidateOptions<TOptions>
where TOptions : class
{
private readonly IServiceProvider _serviceProvider;
private readonly string? _name;
public FluentValidateOptions(IServiceProvider serviceProvider, string? name)
{
_serviceProvider = serviceProvider;
_name = name;
}
public ValidateOptionsResult Validate(string? name, TOptions options)
{
if (_name is not null && _name != name)
{
return ValidateOptionsResult.Skip;
}
ArgumentNullException.ThrowIfNull(options);
using var scope = _serviceProvider.CreateScope();
var validator = scope.ServiceProvider.GetRequiredService<IValidator<TOptions>>();
var result = validator.Validate(options);
if (result.IsValid)
{
return ValidateOptionsResult.Success;
}
var type = options.GetType().Name;
var errors = new List<string>();
foreach (var failure in result.Errors)
{
errors.Add($"Validation failed for {type}.{failure.PropertyName} " +
$"with the error: {failure.ErrorMessage}");
}
return ValidateOptionsResult.Fail(errors);
}
}
📝 نکات مهم درباره این پیادهسازی
یک scoped service provider ساخته میشود تا Validator به درستی Resolve شود (چون Validatorها معمولاً به صورت Scoped ثبت میشوند).
گزینههای دارای نام با استفاده از پراپرتی _name مدیریت میشوند.
پیامهای خطای دقیق و اطلاعاتی ساخته میشوند که شامل نام پراپرتی و پیام خطا هستند.
⚙️ نحوه عملکرد یکپارچهسازی FluentValidation
• اینترفیس <IValidateOptions<T نقطه اتصال ASP.NET Core برای اعتبارسنجی Options است.
• کلاس <FluentValidateOptions<T این اینترفیس را پیادهسازی میکند تا ارتباط با FluentValidation برقرار شود.
• وقتی ()ValidateOnStart فراخوانی میشود، ASP.NET Core همه پیادهسازیهای <IValidateOptions<T را Resolve کرده و اجرا میکند.
• اگر اعتبارسنجی شکست بخورد، OptionsValidationException پرتاب میشود و از شروع برنامه جلوگیری میکند. ✅