Почему ASP.NET MVC заботится о моих свойствах только для чтения во время привязки данных?
-
18-09-2019 - |
Вопрос
Редактировать:Добавлена награда, потому что я ищу решение MVC3 (если оно существует), отличное от этого:
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
У меня есть свойство только для чтения в моей модели «Адрес». 'CityStateZip'
.
Это просто удобный способ узнать город, штат и почтовый индекс с адреса в США.Он выдает исключение, если страна не США (вызывающий абонент должен сначала проверить).
public string CityStateZip
{
get
{
if (IsUSA == false)
{
throw new ApplicationException("CityStateZip not valid for international addresses!");
}
return (City + ", " + StateCd + " " + ZipOrPostal).Trim().Trim(new char[] {','});
}
}
Это часть моей модели, поэтому она привязана.До ASP.NET MVC2 RC2 это поле никогда не вызывало проблем во время привязки данных.Я даже никогда об этом не задумывался - ведь это только чтение.
Теперь, хотя с выпуском RC2 за январь 2010 года он выдает ошибку во время привязки данных - потому что связыватель модели по умолчанию, похоже, хочет проверить это значение (даже если оно доступно только для чтения).
Именно строка base.OnModelUpdated вызывает возникновение этой ошибки.
public class AddressModelBinder : DefaultModelBinder
{
protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
base.OnModelUpdated(controllerContext, bindingContext);
Изменения в привязке моделей в последние минуты, очевидно, вызвали это изменение в поведении - но я пока не совсем уверен, каковы его последствия - или является ли это ошибкой?Я передаю это команде MVC, но мне любопытно, есть ли у кого-нибудь еще какие-либо предложения, как я могу предотвратить привязку этого свойства.
Эту статью стоит прочитать об изменениях, но в ней вообще не упоминаются свойства только для чтения (хотя я этого и не ожидал).Проблема (если она есть) может быть шире, чем эта ситуация - я просто не уверен в каких-либо последствиях - если таковые имеются!
Проверка ввода против.Проверка модели в ASP.NET MVC
По просьбе @haacked вот трассировка стека:
Я получаю это, просто добавляя следующую строку в ЛЮБУЮ модель и отправляя сообщение в соответствующий метод действия.В данном случае я добавил его к своей простейшей модели.
public string Foo { get { throw new Exception("bar"); } }
[ТаргетИнвокацииИсключение:Средство доступа к свойству «Foo» для объекта «Rolling_Razor_MVC.Models.ContactUsModel» выдало следующее исключение: «bar»] System.ComponentModel.ReflectPropertyDescriptor.GetValue(компонент объекта) +390 System.Web.Mvc.<>c__DisplayClassb. <GetPropertyValueAccessor>b__a() +18 System.Web.Mvc.ModelMetadata.get_Model() +22 System.Web.Mvc.ModelMetadata.get_RealModelType() +29 System.Web.Mvc. <GetValidatorsImpl>d__0.MoveNext() +38 System.Linq. <SelectManyIterator>d__14'2.MoveNext() +273 System.Web.Mvc. <Validate>d__5.MoveNext() +644 System.Web.Mvc.DefaultModelBinder.OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext) +92 System.Web.Mvc.DefaultModelBinder.BindComplexElementalModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Объектная модель) +60 System.Web.Mvc.DefaultModelBinder.BindComplexModel(ControllerContext, controllerContext, ModelBindingContext) +1048 System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +280 System.Web.Mvc.Controller.TryUpdateModel(модель TModel, префикс строки, строка[] includeProperties, строка[] excludeProperties, IValueProvider valueProvider) +449 System.Web.Mvc.Controller.TryUpdateModel(модель TModel) +73
Решение
Я считаю, что испытываю аналогичную проблему.Подробности я опубликовал:
http://forums.asp.net/t/1523362.aspx
редактировать:Ответ команды MVC (из URL-адреса выше):
Мы исследовали это и пришли к выводу, что система проверки работает так, как ожидалось.Поскольку проверка модели предполагает попытку выполнить проверку всех свойств, а свойства типа значения, не допускающие значения NULL, имеют неявный атрибут [Required], мы проверяем это свойство и вызываем его метод получения в процессе.Мы понимаем, что это кардинальное изменение продукта по сравнению с версией 1, но необходимо, чтобы новая система проверки модели работала правильно.
У вас есть несколько вариантов обойти это.Любой из них должен работать:
- Измените свойство Date на метод вместо свойства;таким образом он будет игнорироваться платформой MVC.
- Изменить тип свойства на DateTime?вместо ДатеВремя.Это удаляет неявное значение [Обязательно] из этого свойства.
- Снимите статический флаг DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes.Это удаляет неявное [Required] из всех свойств типа значения, не допускающего значения NULL, во всем приложении.Мы рассматриваем возможность добавления в версию продукта 3 атрибута, который будет сигнализировать нам: «не привязывайте его, не проверяйте, просто притворитесь, что этого свойства не существует».
Еще раз спасибо за отчет!
Другие советы
Все еще имею ту же проблему с MVC3.
Я думаю, что лучший способ - это просто сделать это в global.asax (из ответа SevenCentral):
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
Это отключит их всех.
Для меня это выглядит как ошибка.Я совершенно не могу понять, почему ModelBinder должен проверять мои свойства, доступные только для чтения (могут быть некоторые технические подробности, но я определенно не понимаю и не хочу тратить время на это).
Я добавил в свое решение следующий поставщик метаданных модели, чтобы обойти проблему.
protected override CachedDataAnnotationsModelMetadata CreateMetadataPrototype(IEnumerable<Attribute> attributes, Type containerType, Type modelType, string propertyName)
{
var metadata = base.CreateMetadataPrototype(attributes, containerType, modelType, propertyName);
if (metadata.IsReadOnly)
{
metadata.IsRequired = false;
}
return metadata;
}
protected override CachedDataAnnotationsModelMetadata CreateMetadataFromPrototype(CachedDataAnnotationsModelMetadata prototype, Func<object> modelAccessor)
{
var metadata = base.CreateMetadataFromPrototype(prototype, modelAccessor);
if (prototype.IsReadOnly)
{
metadata.IsRequired = false;
}
return metadata;
}
Вам также необходимо добавить следующее в Global.asax.cs
protected void Application_Start()
{
ModelMetadataProviders.Current = new RESModelMetadataProvider();
ModelBinders.Binders.Add(typeof(SmartDate), new SmartDateModelBinder());
...
}
Конечно, я думаю, я мог бы конвертировать CityStateZip
к GetCityStateZip()
но тогда я не могу с такой же легкостью связать его с чем-то вроде серебряного света.Это может помочь в качестве временного решения для тех, кто столкнулся с этой проблемой.
У МЕНЯ ТОЧНО ТАКАЯ ЖЕ ПРОБЛЕМА!!
Для получения дополнительной информации о моей проблеме вы можете посетить ASP.NET MVC 2.0 Неиспользуемое свойство модели вызывается при публикации продукта на сервер?
означает ли это, что нам нужно программировать наши свойства с предположением, что они будут вызываться неожиданно (до того, как свойства, от которых это зависит, будут установлены/инициализированы и т. д.)...если да, то это означает изменение в нашей практике программирования, и мне хотелось бы знать, как действовать дальше.
Между тем, у меня есть простая проверка «если», которая решает проблему.
У меня возникла аналогичная проблема: поле, которое, как я не ожидал, будет проверено, получало ошибку, когда форма отправлялась обратно в контроллер.После некоторого гугления я наткнулся http://codeblog.shawson.co.uk/mvc-strongly-typed-view-returns-a-null-model-on-post-back/ где было указано, что конфликты имен могут вызвать проблемы.
Хотя я не думал, что мой класс переменных обратной передачи имеет конфликтующие имена свойств, переименование свойства, получившего ошибку, решило мою проблему.
Та же проблема все еще существует в MVC 5.2.3, и проблема даже не в коде проверки.Тем DefaultModelBinder
вызывает геттеры вне своего кода проверки, даже если они являются свойствами, доступными только для чтения, и даже если никакие данные запроса не передаются контроллеру, соответствующему этим свойствам.
Более подробное объяснение и мое полное решение смотрите здесь: https://stackoverflow.com/a/54431404/10987278.
Я не уверен, что это решение можно переработать для работы с MVC 3, но надеюсь, что оно поможет другим, которые все еще страдают от той же проблемы в более поздней версии MVC, и которые, как и я, столкнулись с этим вопросом.