SimpleInjector 和 FluentValidationFactory
SimpleInjector and FluentValidationFactory
我正在尝试自动验证我的视图模型,我知道我可以只添加一个属性来指定我的验证,但是有一个选项可以设置一个工厂来自动执行所有这些,我查看了:this answer 并使用简单的注入器 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<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);
}
}
但是实现变量总是null,我也尝试过RegisterCollection但仍然有同样的问题,当验证器继承自AbstractValidator时,简单的注入器似乎不知道如何解析IValidator(这是class 实现 IValidator)
像这样在 Simple Injector 中注册 Fluent Validation Factory:
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);
}
}
然后在您的 Composition Root 中为 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;
}
);
FluentValidationModelValidatorProvider
位于 FluentValidation.MVC
集成包中。记得购买适合您 运行.
版本的 MVC
更新
您可以为没有验证器的对象注册一个空验证器,例如:
/// <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);
我想在这里分享我将 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
s 的模型绑定魔术的视图模型对他们来说,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 显然会减慢验证器的分辨率这一事实并不满意,所以我环顾四周,找到 API 使得 Container
return null 而不是抛出异常。事实证明这是可能的,因为 Container
implements IServiceProvider
explicitly,如果类型未注册,IServiceProvider
将 return null
。
我的第三次也是最后一次尝试,因为这个验证器工厂不再依赖于 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));
}
}
作为一个额外的好处,这有效并将验证器工厂与简单注入器完全解耦。
我正在尝试自动验证我的视图模型,我知道我可以只添加一个属性来指定我的验证,但是有一个选项可以设置一个工厂来自动执行所有这些,我查看了:this answer 并使用简单的注入器 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<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);
}
}
但是实现变量总是null,我也尝试过RegisterCollection但仍然有同样的问题,当验证器继承自AbstractValidator时,简单的注入器似乎不知道如何解析IValidator(这是class 实现 IValidator)
像这样在 Simple Injector 中注册 Fluent Validation Factory:
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);
}
}
然后在您的 Composition Root 中为 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;
}
);
FluentValidationModelValidatorProvider
位于 FluentValidation.MVC
集成包中。记得购买适合您 运行.
更新
您可以为没有验证器的对象注册一个空验证器,例如:
/// <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);
我想在这里分享我将 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
s 的模型绑定魔术的视图模型对他们来说,Simple Injector 会抛出 ActivationException
并使应用程序崩溃。
我的第二次尝试当然是在 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 显然会减慢验证器的分辨率这一事实并不满意,所以我环顾四周,找到 API 使得 Container
return null 而不是抛出异常。事实证明这是可能的,因为 Container
implements IServiceProvider
explicitly,如果类型未注册,IServiceProvider
将 return null
。
我的第三次也是最后一次尝试,因为这个验证器工厂不再依赖于 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));
}
}
作为一个额外的好处,这有效并将验证器工厂与简单注入器完全解耦。