2015-11-03 18 views
2

我想自动化我的视图模型的验证,我知道我可以添加一个属性来指定我的验证,但有一个选项来设置一个工厂来自动化所有,我看着: this answer并想出了这个用简单的喷油器3.1:SimpleInjector和FluentValidationFactory

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<Person> { 
    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); 
    } 
} 

但是实施变量总是空,我也试着RegisterCollection,但仍然有似乎同样的问题喜欢简单的喷油器不知道如何当验证从AbstractValidator继承解决IValidator(这是实现IValidator类)

+0

你为什么要在工厂的构造函数中注册验证器?我很惊讶这个代码甚至可以工作。我想不出为什么你会想要这样的理由。您应该将此代码放在应用程序的组合根目录中。 –

+0

你能展示一个最小可重现的例子吗? CustomValidatorFactory如何注册以及它如何被调用?实际提供给fsctory的参数是什么?工厂是否提供了Typeof(Person)或typeof(IValidator )? – Steven

+0

@ Ric.Net,这个CustomValidatorFactory可以被认为是组合根的一部分,所以在这里做注册似乎很好。 – Steven

回答

5

注册流利验证厂简单喷油器是这样的:

public class ApplicationValidatorFactory : IValidatorFactory 
{ 
    private readonly Container _container; 

    /// <summary>The constructor of the factory.</summary> 
    /// <param name="container">The Simple Injector Container</param> 
    public ApplicationValidatorFactory(Container container) 
    { 
     _container = container; 
    } 

    /// <summary>Gets the validator for the specified type.</summary> 
    public IValidator<T> GetValidator<T>() 
    { 
     return _container.GetInstance<IValidator<T>>(); 
    } 

    /// <summary>Gets the validator for the specified type.</summary> 
    public IValidator GetValidator(Type type) 
    { 
     var validator = typeof(IValidator<>).MakeGenericType(type); 
     return (IValidator)_container.GetInstance(validator); 
    } 
} 

然后在你的作文根注册它ASP.NET MVC:

// Register the validators and factory 
var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList(); 
container.Register<IValidatorFactory, ApplicationValidatorFactory>(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; 
    } 
); 

FluentValidationModelValidatorProviderFluentValidation.MVC集成包中找到。请记住为您正在运行的MVC版本获取一个。

UPDATE

您可以注册为不具有像一个验证对象为空验证:

/// <summary> 
/// Adds an unregistered type resolution for objects missing an IValidator. 
/// </summary> 
/// <typeparam name="T">The type.</typeparam> 
internal sealed class ValidateNothingDecorator<T> : AbstractValidator<T> 
{ 
    // I do nothing :-) 
} 

// Add unregistered type resolution for objects missing an IValidator<T> 
// This should be placed after the registration of IValidator<> 
container.RegisterConditional(typeof(IValidator<>), typeof(ValidateNothingDecorator<>), Lifestyle.Singleton, context => !context.Handled); 
+1

感谢编辑,@Steven - 必须有一些复制/浪费:-) – janhartmann

+1

这个解决方案解决了我的大部分问题,唯一的问题是当有没有验证器的视图模型时抛出一个错误,所以我刚刚替换了这一行: 'return(IValidator)_container.GetInstance (验证器);' 与: '返回((IServiceProvider)_container).GetService(验证器)作为IValidator;' 我认为唯一的区别是,GetService方法将只返回null whi这种情况下可以。 –

+0

@ danif430看到我的更新 – janhartmann

1

我想与大家分享我在这里集成简单的喷油器与FluentValidation经验。

我第一次尝试是类似于@janhartmann一样,实行的具体ValidatorFactoryBase这需要简单的喷油器的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,Simple Injector会抛出ActivationException并导致应用程序崩溃。

我的第二次尝试当然是把一个try-catch块左右GetInstance

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将验证的分辨率显然会慢下来,我环顾所以找到使Container返回null而不是抛出异常的API。原来这是可能的,因为Container implements IServiceProvider explicitlyIServiceProvider将返回null如果类型未注册。

我的第三个,也是最后的尝试,因为这验证工厂不再依赖于简单的喷油器,我把它改名为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)); 
    } 
} 

这工作完全脱钩验证工厂简单的注射器作为附加效益。

相关问题