Как добавить введенные пользовательские атрибуты проверки во время выполнения с помощью Simple Injector?

Сначала я зарегистрировал свой пользовательский атрибут:

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 ответ

Решение

Прежде всего, вы не должны явно регистрировать атрибуты в контейнере, если вы хотите сделать это во время выполнения.

В 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);

Это все.

Другие вопросы по тегам