5

Trying to inject Fluent Validation in .Net Core 3.1 micro service with MediatR without Structure Map.

Added Below Nuget Packages:

<PackageReference Include="FluentValidation.AspNetCore" Version="8.6.2" />
<PackageReference Include="MediatR" Version="4.0.1" />
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="4.0.0" />

Startup.cs:

services.AddMvc(options =>
            {
                options.Filters.Add(typeof(HttpGlobalExceptionFilter));
                options.EnableEndpointRouting = false;
            }).AddControllersAsServices()
            .AddNewtonsoftJson()
            .AddViewLocalization(
                       LanguageViewLocationExpanderFormat.Suffix,
                       opts => { opts.ResourcesPath = "Resources"; })
            .AddDataAnnotationsLocalization()
            .SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
            .AddFluentValidation(fv=> fv.RegisterValidatorsFromAssemblyContaining(typeof(Startup)));

Registered IPipelineBehavior and Validator:

services.AddMediatR();

services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidatorBehaviour<,>));

ValidatorBehaviour.cs:

public class ValidatorBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    {
        private readonly IValidator<TRequest>[] _validators;
        public ValidatorBehaviour(IValidator<TRequest>[] validators) => _validators = validators;

        public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
        {
            var failures = _validators
                .Select(v => v.Validate(request))
                .SelectMany(result => result.Errors)
                .Where(error => error != null)
                .ToList();

            if (failures.Any())
            {
                var errorFieldsMessages = failures.Select(x => x.ErrorMessage + ", ").ToArray();

                throw new PomDetailsException(
                    $"Command Validation Errors for type {typeof(TRequest).Name}. " +
                    $"Validation failed : {string.Join(string.Empty, errorFieldsMessages)}", new ValidationException("Validation exception", failures));
            }

            var response = await next();
            return response;
        }
    }

Exception:

Unable to resolve service for type 'FluentValidation.IValidator`1[][]' while attempting to activate 

I am guessing I have the configuration wrong but I have been changing configuration several times with no success.

Any guidance would be much appreciated

Rahul
  • 63
  • 1
  • 9

1 Answers1

11

You are trying to resolve collection of IValidator<TRequest> so you specified constructor parameter as IValidator<TRequest>[] (array). But the framework's DI requires using IEnumerable for this purpose. Update ValidatorBehaviour constructor as following and it will work as expected

private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidatorBehaviour(IEnumerable<IValidator<TRequest>> validators) => _validators = validators;
Alexander
  • 9,104
  • 1
  • 17
  • 41
  • @Alexander- now getting this error Unable to resolve service for type 'Microsoft.AspNetCore.Http.HttpContextAccessor' while attempting to activate 'PurchaseOrder.API.Application.Pipeline.PurchaseOrderPreprocessor`1[PurchaseOrder.API.Application.Commands.ReopenPomIdToWorkingCommand]'. Already regisistered services.AddSingleton(); – Rahul Aug 02 '20 at 15:10
  • @Rahul Could you please share `PurchaseOrderPreprocessor` code? – Alexander Aug 02 '20 at 15:11
  • private readonly HttpContextAccessor _httpContextAccessor; public PurchaseOrderPreprocessor(HttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } – Rahul Aug 02 '20 at 15:13
  • @Rahul Make type IHttpContextAccessor (added **I** in the beggining) for both constructor argument and field. – Alexander Aug 02 '20 at 15:14
  • Let me try and get back to you in few mins – Rahul Aug 02 '20 at 15:14