Почему ASP.NET MVC заботится о моих свойствах только для чтения во время привязки данных?

StackOverflow https://stackoverflow.com/questions/2211829

Вопрос

Редактировать:Добавлена ​​награда, потому что я ищу решение 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, и которые, как и я, столкнулись с этим вопросом.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top