Как правильно зарегистрировать FluentValidation в SimpleInjector?

Я могу зарегистрировать FluentValidation AbstractValidators используя FluentValidatorFactory, Тем не менее, это не правильно, потому что не все регистрации контейнера IoC происходят во время начальной загрузки / корня композиции. Вместо этого беглые валидаторы регистрируются отдельной фабрикой:

Состав корня:

public class SimpleDependencyInjector : IServiceProvider
{
    public readonly Container Container;

    public SimpleDependencyInjector()
    {
        Container = Bootstrap();
    }

    internal Container Bootstrap()
    {
        var container = new Container();

        container.Register< // ...register all non-fluent-validator types, then

        container.Verify();
        return container;
    }

    public object GetService(Type serviceType)
    {
        return ((IServiceProvider)Container).GetService(serviceType);
    }
}

Абстрактная свободная фабрика валидаторов, зависящая только от IServiceProvider

public abstract class FluentValidatorFactory : ValidatorFactoryBase
{
    private IServiceProvider Injector { get; set; }

    protected FluentValidatorFactory(IServiceProvider injector)
    {
        Injector = injector;
    }

    public override IValidator CreateInstance(Type validatorType)
    {
        return Injector.GetService(validatorType) as IValidator;
    }
}

Свободная реализация фабрики валидаторов для SimpleInjector

public class SimpleValidatorFactory : FluentValidatorFactory
{
    public SimpleValidatorFactory(SimpleDependencyInjector injector) 
        : base(injector)
    {
        var validators = AssemblyScanner.FindValidatorsInAssembly(
            Assembly.GetCallingAssembly());
        validators.ForEach(validator => 
            injector.Container.Register(
                validator.InterfaceType, validator.ValidatorType));
        injector.Container.Verify();
    }
}

SimpleInjector имеет хорошую поддержку открытых обобщений, и все мои беглые классы валидаторов имеют подписи, подобные следующим:

public class SomeClassValidator : AbstractValidator<SomeClass>
{
    public SomeClassValidator([depedencies injected here])
    {
        // ... set up validation rules
    }
}

Итак, есть ли лучший способ зарегистрировать валидаторы в корне начальной загрузки / композиции вместо использования фабрики валидаторов fluent?

PS @DotNetJunkie - было бы здорово, если бы у вас была вики-страница по этому адресу simpleinjector.codeplex.com.

1 ответ

Решение

Я думаю, что я понял это сам.

1.) Зарегистрировать свободный общий IValidator<T> Интерфейс в корне композиции:

public class SimpleDependencyInjector : IServiceProvider
{
    public readonly Container Container;

    public SimpleDependencyInjector()
    {
        Container = Bootstrap();
    }

    internal Container Bootstrap()
    {
        var container = new Container();

        // some container registrations

        var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
        container.RegisterManyForOpenGeneric(typeof(IValidator<>), assemblies);

        // some more registrations

        container.Verify();
        return container;
    }

    public object GetService(Type serviceType)
    {
        return ((IServiceProvider)Container).GetService(serviceType);
    }
}

2.) Избавиться от SimpleValidatorFactory учебный класс.

3.) Сделать FluentValidatorFactory неабстрактный, конкретный класс:

public class FluentValidatorFactory : ValidatorFactoryBase
{
    private IServiceProvider Injector { get; set; }

    public FluentValidatorFactory(IServiceProvider injector)
    {
        Injector = injector;
    }

    public override IValidator CreateInstance(Type validatorType)
    {
        return Injector.GetService(validatorType) as IValidator;
    }
}

4.) Зарегистрируйте FluentValidatorFactory в качестве поставщика фабрики проверки в global.asax:

var injector = new SimpleDependencyInjector();
FluentValidationModelValidatorProvider.Configure(
    provider =>
    {
        provider.ValidatorFactory = new FluentValidatorFactory(injector);
    }
);