Search code examples
c#asp.net-corefluentvalidationasp.net-core-6.0mediatr

ASP.NET Core 6.0 : FluentValidation validators are registered but how?


Currently, I am working on a .NET Core 6.0 project that uses MediatR, Automapper, and FluentValidation.

I understand the FluentValidation validators are registered by using the "AddValidatorsFromAssembly" method like below

    public static void AddApplicationLayer(this IServiceCollection services)
    {
        services.AddAutoMapper(Assembly.GetExecutingAssembly());
        services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
        services.AddMediatR(Assembly.GetExecutingAssembly());
        services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
    }

However, the project I am working on looks like this

    protected internal override void AddServices(IServiceCollection services)
    {
        services.AddMediatR(typeof(Program));

        services.Scan(s => s
                        .FromAssembliesOf(this.AssemblyMarkerTypes)
                        .AddClasses(false)
                        .UsingRegistrationStrategy(RegistrationStrategy.Append)
                        .AsImplementedInterfaces()
                        .WithTransientLifetime());

        services.AddAutoMapper(typeof(Program));

        services.AddControllers();
        services.AddHealthChecks();
        base.AddServices(services);
    }

It is not clear to me how FluentValidation validators are registered without calling AddValidatorsFromAssembly.

Additionally, it is not clear what the following code does.

        services.Scan(s => s
                        .FromAssembliesOf(this.AssemblyMarkerTypes)
                        .AddClasses(false)
                        .UsingRegistrationStrategy(RegistrationStrategy.Append)
                        .AsImplementedInterfaces()
                        .WithTransientLifetime());

If the above scan, register all the DIs, why do we need a separate registrations for AddAutoMapper & AddMediatR?


Solution

  • It seems that project is using Scrutor. Based on provided code it will search in assemblies which contain some subset of types defined by this.AssemblyMarkerTypes for all non-abstract types classes (including non-public) and will register them as all implemented interfaces with transient lifetime.

    Without access to the source code it is hard to argue what subset of assemblies is covered by AssemblyMarkerTypes but usually it should be all or almost all assemblies which are custom developed for the project, including the one containing validators.

    why do we need a separate registrations for AddAutoMapper & AddMediatR

    Those methods also register some internal AutoMapper and MediatR stuff. There are 2 reasons why they would not be covered by Scan - first, the types of assemblies for AutoMapper and MediatR were not included in AssemblyMarkerTypes, and the second reason (basically why they were not included) - library developers added those methods so library consumers do not need to bother with what and how needs to be registered for them to function correctly, cause surely there can be stuff which requires different lifetimes and/or is registered as types (i.e. something like services.AddX<SomeConcreteType>()).