2010-02-06 46 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

相關問題