2010-02-06 50 views
18

编辑:添加赏金,因为我正在寻找一个MVC3的解决方案(如果存在)除此以外:为什么ASP.NET MVC在数据绑定期间关心我的只读属性?

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); 

最后时刻变化的ModelBinder的明显造成的这种行为改变 - 但我不能肯定什么还没有它的repurcussions是 - 或者是否这是不是一个错误?我将此传递给MVC团队,但好奇的是,如果其他人有任何建议,同时我可以如何防止此属性的约束力。

这篇文章非常值得关于这些改变 - 但没有提及只读属性(不是我期望的)。这个问题(如果有的话)可能比这种情况更广泛 - 我只是不确定任何反弹 - 如果有的话!

Input Validation vs. Model Validation in ASP.NET MVC


按照要求通过这里@haacked的堆栈跟踪:

我通过简单地添加以下行任何模型和制作后,以相应的操作方法来获取此。在这个例子中,我将它添加到了我最简单的模型中。

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

[TargetInvocationException:属性访问 '富' 上对象 'Rolling_Razor_MVC.Models.ContactUsModel' 发生以下异常: '栏'] 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。 <验证> 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 model)+73

+0

是什么你看到的确切错误?查看相关的控制器和视图代码也很有帮助。 – 2010-02-06 03:19:54

+0

我们需要更多的细节,但是当我们尝试读取导致异常被抛出的属性时,我的猜测是IsUsa是错误的。不知道为什么我们会在模型绑定期间阅读它,除非在表单中有一个名为“CityStateZip”的表单域。 – Haacked 2010-02-06 03:52:06

+0

@brad以及确切的错误是'CityStateZip对国际地址无效!' ;-) 我使用完整的堆栈跟踪来更新问题。 复制只需将此添加到任何现有的模型,并对相应的actionmethod进行POST: public string Foo {get {throw new Exception(“bar”); }} – 2010-02-06 03:54:46

回答

16

我相信我遇到类似的问题。我已经张贴了细节:

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


编辑:从MVC团队的响应(从上面URL):

我们调查了这一点,并得出结论,验证系统表现为预期。由于模型验证涉及试图对所有属性运行验证,并且由于不可为空的值类型属性具有隐式[必需]属性,因此我们正在验证此属性并在该过程中调用其getter。我们知道这是对产品V1的突破性改变,但有必要使新型号验证系统正确运行。

你有几个选择来解决这个问题。其中任何一个都可以工作:

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

再次感谢您的报告!

+0

检查上述帖子的答案。 – Rudy 2010-02-09 01:08:47

+1

这两个东西没有解决的事实是,我的财产是只读的,所以它不应该永远需要'得到'。所以这个解决方案稍微拧紧了我的设计,但解决方法仍然有效。第二件事是,无论如何,这个事情都会发生异常。那绝对不好。如果模型失败模型失败,但炸毁不好 – 2010-02-09 19:55:34

+0

我有完全相同的问题,请阅读我的回复帖子链接,如果你喜欢。我热切地等待mvc v3,因为在第2版中有太多未解决/缺失的元素,包括这个和能够返回多个视图来更新网页的不同物理区域,更好的定制服务器端验证支持等等。现在解决这些问题,但只有通过使用'黑客',我才不觉得编码的优雅,我应该感觉使用mvc;( - 我不能等到v3。 – 2010-05-06 13:22:55

0

当然,我想我可以将CityStateZip转换为GetCityStateZip(),但之后我无法像Silverlight那样轻松地绑定它。这可能对遇到此问题的其他人暂时修复。

0

我有完全相同的问题!

有关我的问题的详细信息,您可以访问ASP.NET MVC 2.0 Unused Model Property being called when posting a product to the server?

做它取决于属性设置/初始化这意味着我们需要把我们的假设,他们将被意外称为属性编程(前等等)...如果是这样,这代表了我们编程实践的变化,我想知道如何继续。

与此同时,我只是一个简单的'如果'检查,摆脱了这个问题。

+1

一般属性只是为了 - 愚蠢的属性,如果你有太多的商业逻辑,那么是的,你必须做出改变,但你也许应该反正,它的遗憾是他们不能添加某种'不验证'属性,但也许会来对于MVC3 – 2010-05-06 17:40:14

2

仍然存在与MVC3相同的问题。

我认为最好的办法是只此在Global.asax中(从SevenCentral的答案):

DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false; 

这将禁用所有这些

1

这看起来像世界上所有的bug对我来说。我完全不明白为什么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

真棒,这应该是被接受的答案:完全解决源代码的问题。较新版本的MVC有不同的方法名称:'GetMetadataForProperty'。如果你键入'protected override',VS可以自动创建存根, ñ只需添加if语句。 – David784 2017-12-06 19:59:14

相关问题