![](/img/trans.png)
[英]Register a generic Validator using FluentValidation and Autofac
[英]FluentValidation Command Validator not registered by AutoFac
一段時間以來,我一直在為一個問題而苦苦掙扎。 我正在基於 eShopOnContainers GitHub 項目See Here構建一個項目。 我的項目在 asp.net core 2.2 上運行,我正在使用
MediatR 6.0,
我正在使用由命令處理程序處理的 MediatR 命令,並且通過許多文章以及在線 eShopOnContainers 示例,我實現了一個ValidatorBehavior
類,該類實現了IPipelineBehavior
。
public class ValidatorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidatorBehavior(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var context = new ValidationContext(request);
var failures = _validators
.Select(v => v.Validate(context))
.SelectMany(result => result.Errors)
.Where(error => error != null)
.ToList();
if (failures.Any())
{
throw new PlanningDomainException(
$"Command Validation Errors for type {typeof(TRequest).Name}", new ValidationException("Validation exception", failures));
}
var response = await next();
return response;
}
}
我還包含了一個 MediatorModule,就像在示例項目中實現的一樣。
public class MediatorModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterAssemblyTypes(typeof(IMediator).GetType().Assembly)
.AsImplementedInterfaces();
// Get the assembly name
var assembly = typeof(Startup).GetType().Assembly;
// Register all the Command classes (they implement IRequestHandler) in assembly holding the Commands
builder.RegisterAssemblyTypes(assembly)
.AsClosedTypesOf(typeof(IRequestHandler<,>));
// Register the DomainEventHandler classes (they implement INotificationHandler<>)
// in assembly holding the Domain Events
builder.RegisterAssemblyTypes(assembly)
.AsClosedTypesOf(typeof(INotificationHandler<>));
// Register the Command's Validators (Validators based on FluentValidation library)
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.IsClosedTypeOf(typeof(IValidator<>)))
.AsImplementedInterfaces();
builder.Register<ServiceFactory>(context =>
{
var componentContext = context.Resolve<IComponentContext>();
return t => { object o; return componentContext.TryResolve(t, out o) ? o : null; };
});
builder.RegisterGeneric(typeof(LoggingBehavior<,>)).As(typeof(IPipelineBehavior<,>));
builder.RegisterGeneric(typeof(ValidatorBehavior<,>)).As(typeof(IPipelineBehavior<,>));
builder.RegisterGeneric(typeof(TransactionBehaviour<,>)).As(typeof(IPipelineBehavior<,>));
}
}
我的測試控制器是:
[Route("api/[controller]")]
[ApiController]
public class ApplicationsController : ControllerBase
{
private readonly IMediator _mediator;
public ApplicationsController(IMediator mediator)
{
_mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));
}
[HttpPost]
[ProducesResponseType((int)HttpStatusCode.OK)]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
public async Task<IActionResult> Put([FromBody]ApplicationCreateCommand command, [FromHeader(Name = "x-requestid")] string requestId)
{
var c = await _mediator.Send(command);
return c ? Ok() : (IActionResult)BadRequest();
}
}
我有以下問題:
每當我嘗試調用此 API 時,都會收到以下錯誤:
無法解析構造函數“Void .ctor(MediatR.IMediator)”的參數“MediatR.IMediator mediator”。
我通過使用.AddMediatR()
添加中介作為服務來解決這個問題,即使在示例項目中它從未像那樣添加。
ValidatorBehavior
被正確調用,但 CommandValidator 不存在。 _validators
列表實際上是空的,所以沒有進行驗證。我還在命令驗證器中設置了斷點,但沒有被命中。
這是我的命令驗證器:
public class ApplicationCreateCommandValidator : AbstractValidator<ApplicationCreateCommand>
{
public ApplicationCreateCommandValidator()
{
RuleFor(cmd => cmd.CategoryType).NotEmpty().Must(BeValidCategoryType).WithMessage("The category type is not valid.");
RuleFor(cmd => cmd.CompetitionId).NotEmpty().WithMessage("The competition id must be specified.");
RuleFor(cmd => cmd.ParticipantId).NotEmpty().WithMessage("The participant id must be specified.");
}
private bool BeValidCategoryType(int categoryType)
{
return categoryType != 0;
}
}
一切都應該正常工作! 我不明白為什么它不會。 也許我沒有在 autofac 中正確加載命令驗證器,但是,我在網上找到的每個示例代碼都指向相同的注冊方法:
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.IsClosedTypeOf(typeof(IValidator<>)))
.AsImplementedInterfaces();
如果你想仔細看看,我在我的 git hub 帳戶上有這個項目的完整源代碼。 這是 API 。
有人能幫我理解我做錯了什么嗎? 這幾天一直讓我發瘋。
我的配置和你差不多。 我能找到的唯一區別是 start.cs 文件中的以下幾行
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.AddFluentValidation(fv =>
{
fv.RegisterValidatorsFromAssemblyContaining<MediatorModule>();
fv.RunDefaultMvcValidationAfterFluentValidationExecutes = false;
}
);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.