#asp.net-mvc #validation #client-side-validation #validationattribute
#asp.net-mvc #проверка #проверка на стороне клиента #validationattribute
Вопрос:
Я создал пользовательский атрибут проверки CompareLessThan, скопировав ASP.NET MVC 3 CompareAttribute и вместо проверки на равенство я проверяю, чтобы увидеть, что одно свойство меньше другого. При возникновении ошибки на стороне клиента пользователю отображается сообщение «{0} должно быть меньше {1}».
Моя модель настроена следующим образом с отображаемыми атрибутами, ссылающимися на файл ресурсов.
[CompareLessThan("AmountAvailable", ErrorMessageResourceName="CompareLessThan", ErrorMessageResourceType = typeof(Resources.ValidationMessages))]
[Display(Name = "Amount", ResourceType = typeof(Resources.Labels))]
public decimal Amount { get; set; }
[Display(Name = "AmountAvailable", ResourceType = typeof(Resources.Labels))]
public decimal AmountAvailable { get; set; }
Тогда пользовательский метод проверки GetClientValidationRules точно такой же, как и в CompareAttribute
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationLessThanRule(FormatErrorMessage(metadata.DisplayName), FormatPropertyForClientValidation(OtherProperty), this.AllowEquality);
}
Здесь мы генерируем сообщение об ошибке, которое будет отображаться пользователю, если возникнет проблема. Я могу получить отображаемое имя из файла ресурсов для свойства, которое украшено моим пользовательским атрибутом CompareLessThan, но мой вопрос в том, как мне получить отображаемое имя «другого» свойства, с которым мы сравниваем? В методе isValid у нас есть ссылка на ValidationContext, из которого я могу сгенерировать объект PropertyInfo для свойства «other» и, я думаю, получить отображаемое имя. Но в GetClientValidationRules у меня нет к этому доступа.
Я всегда мог просто передать другое значение для отображаемого имени другого свойства, но я надеялся, что будет способ получить его, поскольку я уже указываю его с помощью аннотаций данных.
Есть идеи?
Ответ №1:
По состоянию на ASP.NET MVC 4 вот как мне удалось получить другое свойство:
PropertyInfo otherPropertyInfo =
this.Metadata.ContainerType.GetProperty(attribute.DependentProperty);
Затем я получил Display attribute
из свойства:
var displayAttribute =
otherPropertyInfo.GetCustomAttributes(typeof(DisplayAttribute), true).
FirstOrDefault() as DisplayProperty;
В вашем случае:
// GetName() is important to get the translated name if you're using a resource file...
this.otherPropertyDisplayName = displayAttribute.GetName();
GetName()
ссылка:
Комментарии:
1. Это должно было быть «как DisplayProperty» или «как DisplayAttribute»? Мой не работал для DisplayProperty, но отлично работал для DisplayAttribute. Отличное решение в противном случае.
2. @MVCKarl: Я думаю, вы правы… Возможно, это была небольшая путаница при вводе ответа здесь. Я не могу записать, что именно я сделал в то время. 🙂
Ответ №2:
Ответ, предоставленный nemesv, не работал в качестве метаданных.Свойство модели имеет значение 0. Но благодаря метаданным у нас есть полное имя модели, поэтому можно создать новый экземпляр этой модели, а затем создать новый DataAnnonationsModelMetadataProvider из этого экземпляра create. Оттуда мы можем получить отображаемое имя другого свойства.
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
Type type = Type.GetType(metadata.ContainerType.FullName);
var model = Activator.CreateInstance(type);
var provider = new DataAnnotationsModelMetadataProvider();
var otherMetaData = provider.GetMetadataForProperty(() => model, type, this.OtherProperty);
this.otherPropertyDisplayName = otherMetaData.DisplayName;
yield return new ModelClientValidationLessThanRule(FormatErrorMessage(metadata.DisplayName), FormatPropertyForClientValidation(this.OtherProperty), this.AllowEquality);
}
Мне действительно не нравится это решение (хотя оно работает), поскольку кажется, что должен быть лучший способ. У кого-нибудь еще есть другие идеи?
Ответ №3:
Я не пробовал, но вы можете получить свойства модели с metadata.Properties
помощью свойства
metadata.Properties.Single(p => p.PropertyName == "OtherPropName").DisplayName;
РЕДАКТИРОВАТЬ: поскольку свойства пусты, что вы всегда можете сделать (хотя это очень элегантно). Вы можете сгенерировать метаданные для себя.
var provider = new DataAnnotationsModelMetadataProvider();
var otherMetaData = provider.GetMetadataForProperty(() => metaData.Model, metaData.ModelType, "OtherPropertyName");
Комментарии:
1. Хорошая мысль, но коллекция свойств всегда пуста.
2. @NickOlsen Это печально. Я обновил свой ответ некоторым «обходным путем».
3. Это также не работает как метаданные. Свойство модели — это просто значение 0. Используя вашу логику, я смог найти другой способ сделать это (см. Другой ответ), но мне это не очень нравится. Я надеюсь, что есть лучший способ, который может предоставить кто-то другой.