22

编辑:添加赏金,因为我正在寻找除此之外的 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 之前,此字段在数据绑定期间从未引起问题。我什至从未真正想过它——毕竟它只是只读的。

现在虽然在 2010 年 1 月的 RC2 版本中,它在数据绑定期间给了我一个错误 - 因为默认模型绑定器似乎想要检查这个值(即使它是只读的)。

触发此错误的是“base.OnModelUpdated”行。

public class AddressModelBinder : DefaultModelBinder
{
    protected override void OnModelUpdated(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        base.OnModelUpdated(controllerContext, bindingContext);

模型绑定器的最后几分钟更改显然导致了这种行为变化 - 但我不太确定它的后果是什么 - 或者这是否是一个错误?我正在将此传递给 MVC 团队,但很好奇在此期间是否有其他人有任何建议如何防止此属性绑定。

这篇文章非常值得一读有关这些更改的内容——但根本没有提到只读属性(不是我期望的那样)。问题(如果有的话)可能比这种情况更广泛 - 我只是不确定是否有任何反击 - 如果有的话!

ASP.NET MVC 中的输入验证与模型验证


根据@haacked 的要求,这是堆栈跟踪:

我只需将以下行添加到 ANY 模型并发布到相应的操作方法即可。在这种情况下,我将它添加到我最简单的模型中。

 public string Foo { get { throw new Exception("bar"); } }

[TargetInvocationException:对象“Rolling_Razor_MVC.Models.ContactUsModel”上的属性访问器“Foo”引发以下异常:“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 bindingContext) +1048 System.Web.Mvc.DefaultModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +280 System.Web.Mvc.Controller.TryUpdateModel(TModel model, String prefix, String[] includeProperties, String[] excludeProperties, IValueProvider valueProvider) +449 System.Web.Mvc.Controller.TryUpdateModel(TModel 模型) +73

4

7 回答 7

19

我相信我遇到了类似的问题。我已经发布了详细信息:

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


编辑:MVC 团队的回应(来自上面的 URL):

我们对此进行了调查并得出结论,验证系统的行为符合预期。由于模型验证涉及尝试对所有属性运行验证,并且由于不可为空的值类型属性具有隐式 [Required] 属性,因此我们正在验证此属性并在此过程中调用它的 getter。我们理解这是对产品 V1 的重大更改,但有必要使新的模型验证系统正常运行。

您有几个选项可以解决此问题。这些中的任何一个都应该起作用:

  • 将 Date 属性改为方法而不是属性;这样它将被 MVC 框架忽略。
  • 将属性类型更改为 DateTime?而不是日期时间。这会从此属性中删除隐含的 [Required]。
  • 清除静态 DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes 标志。这从应用程序范围内的所有不可空值类型属性中删除了隐含的 [Required]。我们正在考虑在产品的 V3 中添加一个属性,该属性将向我们发出“不要绑定它,不要验证它,只是假装这个属性不存在”的信号。

再次感谢您的报告!

于 2010-02-08T20:32:20.163 回答
2

MVC3 仍然有同样的问题。

我认为最好的方法是在 global.asax 中做到这一点(来自 SevenCentral 的回答):

 DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;

这将禁用所有这些

于 2011-05-04T01:00:44.573 回答
1

这对我来说就像一个错误一样寻找整个世界。我完全不明白为什么 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());

    ...
}
于 2014-03-14T16:53:33.673 回答
0

当然,我想我可以转换CityStateZip为,GetCityStateZip()但我不能很容易地将它绑定到 Silverlight 之类的东西中。对于遇到此问题的其他任何人,这可能适用于临时修复。

于 2010-02-06T03:06:14.170 回答
0

我有完全一样的问题!!

有关我的问题的更多信息,您可以访问将产品发布到服务器时调用 ASP.NET MVC 2.0 未使用的模型属性?

这是否意味着我们需要对我们的属性进行编程,假设它们会被意外调用(在它所依赖的属性被设置/初始化等之前)......如果是这样,这代表我们的编程实践发生了变化,我会想知道如何进行。

同时,我只有一个简单的“if”检查来解决问题。

于 2010-05-06T13:18:20.263 回答
0

我遇到了类似的问题,当表单发回控制器时,我不希望验证的字段收到错误。经过一番谷歌搜索,我遇到了http://codeblog.shawson.co.uk/mvc-strongly-typed-view-returns-a-null-model-on-post-back/有人指出名称冲突可能造成问题。

虽然我不认为我的回发变量类有冲突的属性名称,但重命名接收错误的属性解决了我的问题。

于 2012-05-10T14:51:15.077 回答
0

同样的问题在 MVC 5.2.3 中仍然存在,甚至不是验证码导致了问题。DefaultModelBinder即使它们是只读属性并且即使没有请求数据被传递给与这些属性匹配的控制器,也会在其验证代码之外调用 getter 。

在此处查看更详细的说明和我的完整解决方案:https ://stackoverflow.com/a/54431404/10987278 。

我不确定该解决方案是否可以重构以与 MVC 3 一起使用,但希望它可以帮助其他人在 MVC 的更高版本中仍然遇到同样的问题,就像我一样偶然发现这个问题。

于 2019-01-30T02:09:35.747 回答