如何使用Simple Injector在运行时添加注入的自定义验证属性?

时间:2014-03-28 14:49:23

标签: runtime data-annotations custom-attributes simple-injector model-validation

首先我注册了我的自定义属性:

container.Register<ValidationAttribute, CustomValidationAttribute>();

我创建了一个自定义DataAnnotationsModelValidatorProvider:

public class CustomModelValidatorProvider : DataAnnotationsModelValidatorProvider
{
    private ValidationAttribute _customValidationAttribute;

    public CustomModelValidatorProvider(
        ValidationAttribute customValidationAttribute) : base()
    {
        _customValidationAttribute = customValidationAttribute;
    }

    protected override IEnumerable<ModelValidator> GetValidators(
        ModelMetadata metadata, ControllerContext context, 
        IEnumerable<Attribute> attributes)
    {
        IList<Attribute> customAttributes = attributes.ToList();

        // It will be added for each property of the model
        customAttributes.Add(_customValidationAttribute);

        IEnumerable<ModelValidator> validators = 
            base.GetValidators(metadata, context, customAttributes);

        return validators;
    }
}

我已将其注册在容器中:

// Register Custom Model Validation Provider
container.Register<DataAnnotationsModelValidatorProvider, CustomModelValidatorProvider>();

我还创建了一个DependencyResolverModelValidatorProvider来让GetValidator方法的提供者能够注入其他生命周期范围实例:

public class DependencyResolverModelValidatorProvider 
    : DataAnnotationsModelValidatorProvider
{
    protected override IEnumerable<ModelValidator> GetValidators(
        ModelMetadata metadata, ControllerContext context, 
        IEnumerable<Attribute> attributes)
    {
        return GetProvider().GetValidators(metadata, context);
    }

    private static DataAnnotationsModelValidatorProvider GetProvider()
    {
        return (DataAnnotationsModelValidatorProvider)
            DependencyResolver.Current.GetService(
                typeof(DataAnnotationsModelValidatorProvider));
    }
}

最后我替换了当前的DataAnnotationsModelValidatorProvider

ModelValidatorProviders.Providers.Remove(
    ModelValidatorProviders.Providers
        .OfType<DataAnnotationsModelValidatorProvider>().First());

ModelValidatorProviders.Providers.Add(new DependencyResolverModelValidatorProvider());

这是使用Simple Injector在运行时添加自定义注入验证属性的好方法吗?

1 个答案:

答案 0 :(得分:1)

首先,如果要在运行时执行此操作,则不应在容器中显式注册属性。

在DataAnnotaionsModelMetadataProvider中,您应该使用GetRegistration方法。

我这样解决这个问题:

1)我的自定义模型元数据提供程序

public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
    private readonly Container container;

    public CustomModelMetadataProvider(Container container)
    {
        this.container = container;
    }

    protected override ModelMetadata CreateMetadata(IEnumerable<Attribute> attributes, Type containerType, Func<object> modelAccessor, Type modelType, string propertyName)
    {
        var dependentAttributeType = typeof(DependentAttribute);

        foreach (var attribute in attributes.Where(i => Attribute.IsDefined(i.GetType(), dependentAttributeType)))
        {
            container.GetRegistration(attribute.GetType(), true).Registration.InitializeInstance(attribute);
        }

        return base.CreateMetadata(attributes, containerType, modelAccessor, modelType, propertyName);
    }
}

2)我的自定义属性(符号DependentAttribute),用于在模型元数据提供程序中识别

[Dependent]
public class RequiredAttribute : System.ComponentModel.DataAnnotations.RequiredAttribute, IClientValidatable
{
    [Dependency]
    public IResourceReader ResourceReader { get; set; }

    public override bool IsValid(object value)
    {
        return base.IsValid(value);
    }

    public override string FormatErrorMessage(string name)
    {
        return ResourceReader.Get(ErrorMessageResourceName);
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        yield return new ModelClientValidationRule
        {
            ValidationType = "required",
            ErrorMessage = FormatErrorMessage(metadata.DisplayName)
        };
    }
}

3)我在代码

中仅在启动时注册我的模型元数据提供程序
ModelMetadataProviders.Current = new CustomModelMetadataProvider(container);

多数人。