SimpleInjector和FluentValidationFactory

我正在尝试自动validation我的视图模型,我知道我可以添加一个属性来指定我的validation但是有一个选项可以设置工厂来自动化所有这些,我看着: 这个答案并提出来了这使用简单的注射器3.1:

public class CustomValidatorFactory:ValidatorFactoryBase { private readonly Container siContainer; public CustomValidatorFactory(Container siContainer) { var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList(); this.siContainer = siContainer; this.siContainer.Register(typeof(IValidator), assemblies); } public override IValidator CreateInstance(Type validatorType) { //var instances = siContainer.GetAllInstances(validatorType); var implementation = ((IServiceProvider)siContainer).GetService(validatorType); var validatorInstance = implementation != null ? (implementation as IValidator) : null; return validatorInstance; } } 

然后视图模型可以是这样的

 public class Person { public int Id { get; set; } public string Name { get; set; } public string Email { get; set; } public int Age { get; set; } } public class PersonValidator : AbstractValidator { public PersonValidator() { RuleFor(x => x.Id).NotNull(); RuleFor(x => x.Name).Length(0, 10); RuleFor(x => x.Email).EmailAddress(); RuleFor(x => x.Age).InclusiveBetween(18, 60); } } 

但是实现变量总是为null,我也尝试过RegisterCollection但仍然有相同的问题,看起来简单的注入器不知道如何在validation器inheritance自AbstractValidator时解析IValidator(这是实现IValidator的类)

在Simple Injector中注册Fluentvalidation工厂,如下所示:

 public class ApplicationValidatorFactory : IValidatorFactory { private readonly Container _container; /// The constructor of the factory. /// The Simple Injector Container public ApplicationValidatorFactory(Container container) { _container = container; } /// Gets the validator for the specified type. public IValidator GetValidator() { return _container.GetInstance>(); } /// Gets the validator for the specified type. public IValidator GetValidator(Type type) { var validator = typeof(IValidator<>).MakeGenericType(type); return (IValidator)_container.GetInstance(validator); } } 

然后在您的Composition Root中为ASP.NET MVC注册它:

 // Register the validators and factory var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList(); container.Register(Lifestyle.Singleton); container.Register(typeof(IValidator<>), assemblies); // Register Simple Injector validation factory in FV FluentValidationModelValidatorProvider.Configure(provider => { provider.ValidatorFactory = new ApplicationValidatorFactory(container); provider.AddImplicitRequiredValidator = false; } ); 

FluentValidationModelValidatorProvider可在FluentValidation.MVC集成包中找到。 记得为你正在运行的MVC版本获取一个。

UPDATE

您可以为没有validation器的对象注册一个空的validation器,如:

 ///  /// Adds an unregistered type resolution for objects missing an IValidator. ///  /// The type. internal sealed class ValidateNothingDecorator : AbstractValidator { // I do nothing :-) } // Add unregistered type resolution for objects missing an IValidator // This should be placed after the registration of IValidator<> container.RegisterConditional(typeof(IValidator<>), typeof(ValidateNothingDecorator<>), Lifestyle.Singleton, context => !context.Handled); 

我想分享我在这里集成Simple Injector和FluentValidation的经验。

我的第一次尝试类似于@janhartmann所做的,实现了一个具体的ValidatorFactoryBase ,它将Simple Injector的Container作为依赖:

 public class SimpleInjectorValidatorFactory : ValidatorFactoryBase { private readonly Container _container; public SimpleInjectorValidatorFactory(Container container) => _container = container; public override IValidator CreateInstance(Type validatorType) => (IValidator)_container.GetInstance(validatorType); } public static class CompositionRoot { public static void RegisterDependencies() { var container = new Container(); FluentValidationModelValidatorProvider.Configure( provider => provider.ValidatorFactory = new SimpleInjectorValidatorFactory(container)); } } 

但是,这是有效的,我在ASP.NET MVC项目的上下文中使用此工厂,并且对于依赖于没有IValidator注册IValidator的模型绑定魔术的视图模型,Simple Injector抛出ActivationException并崩溃应用。

我的第二次尝试当然是在GetInstance周围放置一个try-catch块:

 public class SimpleInjectorValidatorFactory : ValidatorFactoryBase { private readonly Container _container; public SimpleInjectorValidatorFactory(Container container) => _container = container; public override IValidator CreateInstance(Type validatorType) { try { object validator = _container.GetInstance(validatorType); return (IValidator)validator; } catch (ActivationException) { // FluentValidation will handle null properly return null; } } } 

但是后来我不满意try-catch显然会降低validation器的分辨率,所以我环顾四周找到使Container返回null而不是抛出exception的API。 事实certificate这是可能的,因为Container显式地实现了IServiceProvider ,如果没有注册类型, IServiceProvider将返回null

我的第三次也是最后一次尝试,并且由于此validation器工厂不再依赖于Simple Injector,我已将其重命名为ServiceProviderValidatorFactory

 public class ServiceProviderValidatorFactory : ValidatorFactoryBase { private readonly IServiceProvider _serviceProvider; public ServiceProviderValidatorFactory(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; public override IValidator CreateInstance(Type validatorType) => (IValidator)_serviceProvider.GetService(validatorType); } public static class CompositionRoot { public static void RegisterDependencies() { var container = new Container(); FluentValidationModelValidatorProvider.Configure( provider => provider.ValidatorFactory = new ServiceProviderValidatorFactory(container)); } } 

这可以使validation器工厂与Simple Injector完全解耦,这是一个额外的好处。