Насколько плохо использовать отражение в ModelValidationProvider? - PullRequest
2 голосов
/ 31 марта 2011

В настоящее время я пытаюсь найти способ упростить использование ErrorMessage из DataAnnotations.После прочтения темы наиболее распространенное решение (создание класса на основе каждого атрибута и автоматическое определение ErrorMessageResourceName и ErrorMessageResourceType) меня не радует.Поэтому я решил переопределить ModelValidationProvider.

К сожалению, мне пришлось прибегнуть к Reflection в моем решении, и я хорошо осведомлен о стоимости производительности от этой техники.Я уже рассматриваю "кэширование" информации о свойствах для каждого modelValidator, чтобы мне не приходилось каждый раз запускать GetProperties.Любое другое предложение / критика для использования этого подхода?

public class LocalizedDataAnnotationsModelValidatorProvider : DataAnnotationsModelValidatorProvider
{
    protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
    {
        var baseReturn = base.GetValidators(metadata, context, attributes);
        var resourceManager = Validation.ResourceManager;
        var culture = Thread.CurrentThread.CurrentUICulture;

        foreach (var modelValidator in baseReturn)
        {
            var type = modelValidator.GetType();
            var attributeProp = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance).FirstOrDefault(x => x.Name == "Attribute");

            var attribute = attributeProp.GetValue(modelValidator, null) as ValidationAttribute;

            if (attribute != null)
            {
                if (string.IsNullOrEmpty(attribute.ErrorMessage))
                {
                    var attributeName = attribute.GetType().Name.Replace("Attribute", string.Empty);
                    attribute.ErrorMessage = resourceManager.GetString(attributeName, culture);
                }
            }
        }

        return baseReturn;
    }
}

Ответы [ 4 ]

2 голосов
/ 31 марта 2011

Это плохо, потому что это не нужно.

Я не вижу, что вы получаете от отражения, когда вы можете просто сделать:

foreach (var modelValidator в baseReturn){if (modelValidator - это DataAnnotationsModelValidator) {var attribute = ((DataAnnotationsModelValidator) modelValidator) .Attribute;if (attribute! = null && string.IsNullOrEmpty (attribute.ErrorMessage)) {var attributeName = attribute.GetType (). Name.Replace ("Атрибут", string.Empty);attribute.ErrorMessage = resourceManager.GetString (attributeName, culture);}}}}

Обновление, которое не работает, поскольку свойство Attribute равно protected internal.Но вы все равно можете сделать:

  foreach(var validationAttribute in attributes.OfType<ValidationAttribute>()){
            var attributeName = attribute.GetType().Name.Replace("Attribute", string.Empty);
            attribute.ErrorMessage = resourceManager.GetString(attributeName, culture);
  }
2 голосов
/ 31 марта 2011

Хорошо, кэширование информации о свойствах - это один из способов, но я бы посоветовал вам взглянуть на Reflection.Emit.

Вот хороший пример того, как ускорить доступ к динамическим свойствам (вместо стандартного отражения GetValue): HyperDescriptor: Ускоренный доступ к динамическим свойствам

Используя Reflection.Emit, вы получите гораздо лучшие результаты.

1 голос
/ 31 марта 2011

Это совсем не плохо.Не беспокойся об этом.

Используя подобную технику, я редко получал более 60 мс накладных расходов при отражении.Не преждевременно оптимизируйте.

Как только это приложение будет запущено в производство, вы почти гарантированно получите больше отдачи от оптимизации хранимых процедур и размеров файлов мультимедиа для сокращения времени загрузки.

0 голосов
/ 31 марта 2011

Ваш лучший / самый простой вариант - перебирать сборку при запуске приложения и кэшировать все, что вы можете.

...