FluentValidation within MediatR pipeline using .NET Core's default DI container
See original GitHub issueI would greatly appreciate it if someone could help me to integrate FluentValidation into the MediatR pipeline using .NET Core’s default DI container.
I have the following classes which represent my request, my handler, and my FluentValidation Validator: `
public class SimpleRequestRequest : IRequest<string>
{
public int Id { get; set; }
}
public class SimpleRequestRequestValidator : AbstractValidator<SimpleRequestRequest>
{
public SimpleRequestRequestValidator(SimpleRequestRequest request)
{
RuleFor(m => m.Id).MustAsync(BeValidIdAsync).WithMessage("Id must be greater than 0, it is {PropertyValue}");
}
private Task<bool> BeValidIdAsync(int id, CancellationToken cancellationToken)
{
return Task.FromResult( id > 0);
}
}
public class SimpleRequestHandler : IRequestHandler<SimpleRequestRequest, string>
{
public Task<string> Handle(SimpleRequestRequest request, CancellationToken cancellationToken)
{
return Task.FromResult($"Request was for {request.Id}");
}
}
`
In order to inject FluentValidation, I have created the following behavior class: `
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}
public 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(f => f != null)
.ToList();
if (failures.Count != 0)
{
throw new ValidationException(failures);
}
return next();
}
}
`
Within my ASP.NET Core (2.1) WebApi, I have the following controller: `
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
private readonly IMediator _mediator;
public TestController(IMediator mediator)
{
_mediator = mediator;
}
// GET api/values/5
[HttpGet("{id}")]
public Task<string> Get(int id)
{
return _mediator.Send(new SimpleRequestRequest {Id = id});
}
}
`
What I would like to have happen is when the controller calls _mediator.Send, I would like the Validation to run. I have this working in a non .NET core solution using the IRequestPreProcessor interface. I am just trying to update things so that I can do the same type of thing within .NET Core.
I believe my struggle is in registering the services. This is in the Startup.cs file. `
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddFluentValidation(fv=> fv.RegisterValidatorsFromAssemblyContaining(typeof(SimpleRequestRequestValidator)));
services.AddMediatR(typeof(SimpleRequestHandler).Assembly);
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
AssemblyScanner.FindValidatorsInAssembly(typeof(SimpleRequestHandler).Assembly)
.ForEach(result =>
{
Console.WriteLine("Here we are");
//services.AddScoped(result.InterfaceType, result.ValidatorType);
services.AddTransient(result.InterfaceType, result.ValidatorType);
}
);
}
`
Within this, I don’t think I need to call AddFluentValidation on the AddMvc builder. I really am not trying to overwrite the validation on the Web-API controllers. I just want it on the MediatR portion.
The issue I am running into, however, is when I call the WebAPI controller. It gets to _mediator.Send, and it throws the following error: Unable to resolve service for type ‘MediatrSample.DLL.BLL.Requests.SimpleRequestRequest’ while attempting to activate ‘MediatrSample.DLL.BLL.Requests.SimpleRequestRequestValidator’.
It is like the DI container for .NET Core doesn’t know how to create the SimpleRequestRequest to pass into the Validator.
Any thoughts or ideas? I have found a number of articles that use things like AutoFac for the DI Container, but I am trying to use the default DI in .NET Core.
Ideally, I don’t want to have to register all validation and request classes. I would rather it discovers it automatically. I thought that is what I was doing with the AssemblyScanner, but apparently not.
Thank you!
Issue Analytics
- State:
- Created 5 years ago
- Reactions:4
- Comments:13 (3 by maintainers)
Top GitHub Comments
maybe it will be useful for other developers who will face the issue like me. So my issue was in collection type for IValidator<TRequest> validators, because I was using IList and was getting the error something like -
Unable to resolve service for type 'System.Collections.Generic.IList1[FluentValidation.IValidator...
Finally, after replacing the IList type on IEnumerable, this error was disappeared. It means that the container can be set up to resolve only for IEnumerable collectionI know it is late to answer but u can use:
services.AddValidatorsFromAssemblyContaining(typeof(yourCommandValidator));