1

Everything is working fine except IValidator injection.

I get an error like below:

Autofac.Core.DependencyResolutionException: 'An error occurred during the activation of a particular registration. See the inner exception for details. Registration: Activator = SampleCommandHandler (ReflectionActivator), Services = [MyApp.Domain.Core.ICommandHandler`1[[MyApp.Domain.SampleCommand, MyApp.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]], Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = None, Ownership = OwnedByLifetimeScope'

Inner Exception DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'MyApp.Domain.SampleCommandHandler' can be invoked with the available services and parameters: Cannot resolve parameter 'FluentValidation.IValidator1[MyApp.Domain.SampleCommand] sampleCommandValidator' of constructor 'Void .ctor(MyApp.Domain.ISampleRepository, FluentValidation.IValidator1[MyApp.Domain.SampleCommand])'.

My application is Web API... And my reference project: https://github.com/Weapsy/Weapsy.CMS

namespace MyApp.Service.WebAPI
{
    /// <summary>
    /// http://autofac.readthedocs.io/en/latest/register/scanning.html#scanning-for-modules
    /// </summary>
    public class AutofacModule : Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            // MyApp.Application.Core
            builder.RegisterAssemblyTypes(typeof(IService).GetTypeInfo().Assembly).AsImplementedInterfaces();

            // MyApp.Application
            builder.RegisterAssemblyTypes(typeof(ISampleService).GetTypeInfo().Assembly).AsImplementedInterfaces();

            // MyApp.Domain.Core
            builder.RegisterAssemblyTypes(typeof(IResolver).GetTypeInfo().Assembly).AsImplementedInterfaces();

            // MyApp.Domain
            builder.RegisterAssemblyTypes(typeof(ISampleRepository).GetTypeInfo().Assembly).AsImplementedInterfaces();
            //builder.RegisterAssemblyTypes(typeof(SampleApplyCommand).GetTypeInfo().Assembly).AsImplementedInterfaces();

            // MyApp.Infrastructure.Data
            builder.RegisterAssemblyTypes(typeof(IDbFactory).GetTypeInfo().Assembly).AsImplementedInterfaces();   
        }
    }
}

namespace MyApp.Service.WebAPI
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            var builder = new ContainerBuilder();
            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
            builder.RegisterModule(new AutofacModule());
            var container = builder.Build();
            config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

            // Web API routes
            config.MapHttpAttributeRoutes();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}

namespace MyApp.Domain
{
    public class SampleCommandHandler : ICommandHandler<SampleCommand>
    {
        private readonly ISampleRepository _sampleRepository;
        private readonly IValidator<SampleCommand> _sampleCommandValidator;

        public SampleCommandHandler(ISampleRepository sampleRepository, IValidator<SampleCommand> sampleCommandValidator)
        {
            _sampleRepository = sampleRepository;
            _sampleCommandValidator = sampleCommandValidator;
        }

        public IEnumerable<IEvent> Handle(SampleCommand command)
        {
            var validate = _sampleCommandValidator.Validate(command);
            if (!validate.IsValid)
            {
                throw new DomainException(validate.Errors.Select(s => s.ErrorMessage));
            }

            var sample = _sampleRepository.Read(command.SampleNumber);

            sample.Apply(command);

            _sampleRepository.Update(sample);

            return sample.Events;
        }
    }
}

namespace MyApp.Domain
{
    public class SampleCommand : ICommand
    {
        public SampleCommand()
        {
        }

        public SampleCommand(string sampleNumber)
        {
            SampleNumber = sampleNumber;
        }

        public string SampleNumber { get; set; }
    }
}

namespace MyApp.Domain
{
    public class SampleValidator<T> : AbstractValidator<T> where T : SampleCommand
    {
        private readonly ISampleRules _sampleRules;

        public SampleValidator(ISampleRules sampleRules)
        {
            _sampleRules = sampleRules;

            RuleFor(rule => rule.SampleNumber)
                .NotEmpty().WithMessage(DomainValidationMessages.SampleNumberCannotBeEmpty);
        }
    }
}

namespace MyApp.Domain.Core
{
    public interface IResolver
    {
        T Resolve<T>();
        IEnumerable<T> ResolveAll<T>();
    }
}

namespace MyApp.Domain.Core
{
    public class AutofacResolver : IResolver
    {
        private readonly IComponentContext _context;

        public AutofacResolver(IComponentContext context)
        {
            _context = context;
        }

        public T Resolve<T>()
        {
            return _context.Resolve<T>();
        }

        public IEnumerable<T> ResolveAll<T>()
        {
            return _context.Resolve<IEnumerable<T>>().ToList();
        }
    }
}

Layers:

MyApp.Service.WebAPI

MyApp.Application

MyApp.Application.Core

MyApp.Domain

MyApp.Domain.Core

MyApp.Infrastructure.Data

I have tried everything to solve but didn't work. Help!

2 Answers 2

0

I cannot tell for sure without seing your actual project, but the Weapsy sample app relies on the fact that all assemblies (including Domain assembly which contains references to IValidator interfaces), get registered by using a class or interface from each one on AutofacModule:

var infrastructureAssembly = typeof(AggregateRoot).GetTypeInfo().Assembly;
var domainAssembly = typeof(CreateSite).GetTypeInfo().Assembly;
var dataAssembly = typeof(IDataProvider).GetTypeInfo().Assembly;
var reportingAssembly = typeof(GetAppAdminModel).GetTypeInfo().Assembly;
var servicesAssembly = typeof(IMailService).GetTypeInfo().Assembly;

However from the trimmed down code you provided, looks like the domain assembly where the validators belong to, does not get registered:

builder.RegisterAssemblyTypes(typeof(IDbFactory).GetTypeInfo().Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof(IResolver).GetTypeInfo().Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof(ISampleRepository).GetTypeInfo().Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof(IService).GetTypeInfo().Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof(ISampleService).GetTypeInfo().Assembly).AsImplementedInterfaces();

Looks like a registration of a type inside the validators assembly could make it work:

builder.RegisterAssemblyTypes(typeof(SampleApplyCommand).GetTypeInfo().Assembly).AsImplementedInterfaces();

If not, make sure you are registering the assembly where the validator implementations reside.

This pattern for registering dependencies can be very opaque, making hard to reason about what dependencies get registered, I would recommend you to be explicit in your registrations and split them between assemblies by using Autofac modules.

Sign up to request clarification or add additional context in comments.

2 Comments

I have added projects layers (edited on post). I have already tried before that you said. But still not working.
I have found an example in this blog (niisar.blogspot.com.tr/2016/04/…). Somebody got the same error before. You can see on comments. :/
0

I went through this problem today while converting a .NetFramework 4.6.2 C# solution to .NET Core 3.1. The earlier working IValidator which had the syntax like

public class Handler {
  // Fluent Validation - Dependency Injection
  public Handler(IValidator <Customer> CustomerValidator) {
  // some code
  }
}

when injected into the constructor worked nicely with .NET standard but errored that way in the .NET Core solution. I referred to this link and was able to use the validator in the following manner. (note that I did not inject the validator into the constructor)

var validator = new CustomerValidator();
var customer = new Customer();

An important step was to register the IValidator in the Startup class.

            // Register fluent validator
            services.AddMvc().AddFluentValidation();
            services.AddTransient<IValidator<Customer>, CustomerValidator>();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.