2015-11-03 33 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)); 
    } 
} 

這工作完全脫鉤驗證工廠簡單的注射器作爲附加效益。

相關問題