2011-08-23 64 views
0

預警:我對MVC及其範例及其一些內部工作原理相對陌生,但我對它很滿意。這是我第二個從頭開始的MVC應用程序,我對如何解決我們測試人員發現的一個「問題」有點困惑。ASP.NET MVC UpdateModel()參數轉換問題

用戶得到的是一個編輯屏幕,它給出了來自財政部(百分比)的每日LIBOR利率的生效日期。費率總是在0到100之間,因此我試圖在我的一個域對象的元數據中使用RangeAttribute來限制該範圍。我指定的範圍內,像這樣:

[Required, DisplayName("Published Rate"), Range(typeof(decimal), "0", "100")] 
public object PublishedRate { get; set; } 

請注意,我傳遞的字符串值作爲RangeAttribute沒有一個重載的構造函數小數。這似乎工作的偉大,直到用戶進入並輸入了一些與衆不同的,如:

「0.000000000000000000000000000000001」

這將導致UpdateModel()失敗; ModelState顯示此錯誤(對於相同的ModelState值,奇怪地是三次):

從類型'System.String'到類型'System.Decimal'的參數轉換失敗。

挖掘錯誤可以揭示原因。下面的第一行是該領域驗證報告的內容。我覺得奇怪的是,這並不能上升到模型驗證錯誤(即在模型中總結驗證列表不顯示):「0.000000000000000000000000000000001不是十進制有效值」

「對於十進制,值或者太大或者太小。」

System.Web.Mvc.ValueProviderResult.ConvertSimpleType() and System.ComponentModel.BaseNumberConverter.ConvertFrom() are throwing the exception。

用戶永遠不會輸入這樣的值,但我不介意知道是否有任何內置於MVC的機制可以或可以防止這種情況(即服務器端)。似乎沒有像以下這樣的數字有問題,它似乎只與非常小的數字打破。

「0.555555555555555555555555555555555」

在這一天結束時,我真的只需要精度9位。支持這些值的數據庫表列是decimal(9,6)。我知道我可以爲我的模型實現一個自定義模型綁定器,並手動從請求中收集這些值,但必須要稍微簡單些,例如自定義FilterAttribute或其他可以在嘗試綁定之前更正該值的東西模型,我只是不確定是什麼,並且正在尋找建議。

我似乎回想起嘗試使用RangeAttribute限制小數值的一些問題,但我不記得這個問題。也許你在那裏的MVC專家可以揭示這種情況。

回答

0

因此,經過幾個小時的頭部撞擊,我定下了小數點後面的自定義模型綁定器。它確保所有十進制值在綁定它們之前都是可解析的。

public class TreasuryIndexRateDecimalBinder : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     var providerResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); 
     if (providerResult != null) 
     { 
      decimal value; 
      if (!decimal.TryParse(providerResult.AttemptedValue, NumberStyles.Float, CultureInfo.CurrentCulture, out value)) 
      { 
       // TODO: Decide whether to show an error 
       // bindingContext.ModelState.AddModelError(bindingContext.ModelName, "error message"); 
       return 0m; 
      } 
      return Math.Round(value, 6); 
     } 
     return base.BindModel(controllerContext, bindingContext); 
    } 
} 

該綁定在Application_Start()中設置,爲所有十進制值進行註冊。

protected void Application_Start() 
{ 
    ModelBinders.Binders.Add(typeof(decimal), new TreasuryIndexRateDecimalBinder()); 

    AreaRegistration.RegisterAllAreas(); 
    RegisterRoutes(RouteTable.Routes); 
} 

,除非有人帶有一個更有趣的方式沿着我想我會用這根棍子。

0

您可以使用正則表達式屬性將十進制數的精度設置爲9.這也可以讓您在正則表達式失敗時添加自定義消息,例如「您的值在小數點後可能最多有9個位置「。或類似的東西。另外,如果您啓用了客戶端驗證,則正則表達式將在客戶端和服務器端驗證中起作用。