Почему ASP.NET MVC заботится о моих свойствах только для чтения во время привязки данных? - PullRequest
20 голосов
/ 06 февраля 2010

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

[TargetInvocationException: средство доступа к свойству 'Foo' для объекта 'Rolling_Razor_MVC.Models.ContactUsModel' выдало следующее исключение: 'bar'] System.ComponentModel.ReflectPropertyDescriptor.GetValue (компонент объекта) +390 System.Web.Mvc. <> C__DisplayClassb. b__a () +18 System.Web.Mvc.ModelMetadata.get_Model () +22 System.Web.Mvc.ModelMetadata.get_RealModelType () +29 System.Web.Mvc. d__0.MoveNext () +38 System.Linq. d__14`2.MoveNext () +273 System.Web.Mvc. 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 bindingContext) +1048 System.Web.Mvc.DefaultModelBinder.BindModel (ControllerContext controllerContext, ModelBindingContext bindingContext) +280 System.Web.Mvc.Controller.TryUpdateModel (модель TModel, префикс String, String [] includeProperties, String [] excludeProperties, IValueProvider valueProvider) +449 System.Web.Mvc.Controller.TryUpdateModel (модель TModel) + 73

Ответы [ 7 ]

17 голосов
/ 08 февраля 2010

Мне кажется, у меня похожая проблема. Я разместил детали:

http://forums.asp.net/t/1523362.aspx


edit : Ответ команды MVC (с URL выше):

Мы исследовали это и пришли к выводу, что система валидации работает так, как ожидалось. Поскольку проверка модели включает в себя попытку запустить проверку всех свойств, а свойства типа, не допускающие значения NULL, имеют неявный атрибут [Required], мы проверяем это свойство и вызываем его метод получения в процессе. Мы понимаем, что это серьезное изменение по сравнению с версией V1 продукта, но необходимо обеспечить правильную работу новой системы проверки модели.

У вас есть несколько вариантов, чтобы обойти это. Любой из них должен работать:

  • Измените свойство Date на метод вместо свойства; таким образом, он будет игнорироваться инфраструктурой MVC.
  • Изменить тип свойства на DateTime? вместо DateTime. Это удаляет неявное [Обязательное] из этого свойства.
  • Очистить статический флаг DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes. Это удаляет неявный [Обязательный] из всех ненулевых свойств типа значения во всем приложении. Мы рассматриваем возможность добавления в V3 продукта атрибута, который будет сигнализировать нам: «не связывайте его, не проверяйте его, просто притворяйтесь, что это свойство не существует».

Еще раз спасибо за отчет!

2 голосов
/ 04 мая 2011

По-прежнему проблема та же с MVC3.

Я думаю, что лучше всего это сделать в global.asax (из ответа SevenCentral):

 DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

Это отключит их всех

1 голос
/ 14 марта 2014

Это выглядит для всего мира как ошибка для меня. Я полностью не могу понять, почему 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());

    ...
}
0 голосов
/ 30 января 2019

Та же проблема все еще существует в MVC 5.2.3, и это даже не код проверки, вызывающий проблему. DefaultModelBinder вызывает геттеры вне своего кода проверки, даже если они являются свойствами только для чтения, и даже если данные запроса не передаются в контроллер, соответствующий этим свойствам.

См. Более подробное объяснение и мое полное решение здесь: https://stackoverflow.com/a/54431404/10987278.

Я не уверен, что это решение можно реорганизовать для работы с MVC 3, но, надеюсь, оно может помочь другим, все еще страдающим от той же проблемы в более поздней версии MVC, которая наткнулась на этот вопрос, как и я.

0 голосов
/ 10 мая 2012

У меня была похожая проблема, поле, которое я не ожидал проверить, получало сообщение об ошибке, когда форма отправлялась обратно в контроллер. После некоторого поиска я наткнулся на http://codeblog.shawson.co.uk/mvc-strongly-typed-view-returns-a-null-model-on-post-back/, где было указано, что конфликты имен могут вызвать проблемы.

Хотя я и не думал, что у моего класса переменных post-back были конфликтующие имена свойств, переименование свойства, получившего ошибку, решило мою проблему.

0 голосов
/ 06 мая 2010

У меня точно такая же проблема !!

Для получения дополнительной информации о моей проблеме вы можете посетить Неиспользуемое свойство модели ASP.NET MVC 2.0, вызываемое при публикации продукта на сервере?

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

Между тем, у меня есть простая проверка «если», которая устраняет проблему.

0 голосов
/ 06 февраля 2010

Конечно, я думаю, что смогу конвертировать CityStateZip в GetCityStateZip(), но тогда я не смогу так же легко связать его в нечто вроде серебряного света. Это может сработать для временного исправления для всех, кто столкнулся с этой проблемой.

...