簡體   English   中英

ASP.NET MVC UpdateModel()參數轉換失敗

[英]ASP.NET MVC UpdateModel() parameter conversion woes

一個警告:我對MVC及其范例以及其某些內部功能還比較陌生,但是我對此很滿意。 這是我的第二個基礎MVC應用程序,我對如何解決其中一個測試人員遇到的“問題”感到有些困惑。

用戶得到的是一個編輯屏幕,其中給出了來自國庫券的每日LIBOR利率的有效日期(百分比)。 速率始終在0到100之間,因此,我嘗試使用域對象之一的元數據中的RangeAttribute來限制該范圍。 我已指定范圍如下:

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

請注意,我要傳遞字符串值,因為RangeAttribute沒有采用小數的重載構造函數。 在用戶進入並輸入與眾不同的內容之前,這似乎非常有效,例如:

“ 0.000000000000000000000000000000000000001”

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

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

深入研究錯誤可以找出原因。 下面的第一行是該字段的驗證報告的內容。 我很好奇這沒有引起模型驗證錯誤(即未出現在模型的摘要驗證列表中):

“ 0.000000000000000000000000000000000000001不是十進制的有效值。” “對於小數,值太大或太小。”

System.Web.Mvc.ValueProviderResult.ConvertSimpleType()System.ComponentModel.BaseNumberConverter.ConvertFrom()引發異常。

用戶永遠不會輸入這樣的值,但是我不介意知道MVC中是否內置有任何機制可以(或將防止這種情況)(服務器端)。 像下面這樣的數字似乎沒有問題,只是看起來很小。

“ 0.555555555555555555555555555555555555”

歸根結底,我真的只需要9位數的精度。 支持這些值的數據庫表decimal(9,6) 我知道我可以為我的模型實現自定義模型綁定程序並從Request中手動收集值,但是必須有一些簡單的方法,例如自定義FilterAttribute或可以在嘗試將其綁定到該值之前更正該值的東西。該模型,我不確定是什么,並且正在尋找建議。

我似乎回想過有關嘗試使用RangeAttribute約束十進制值的一些問題,但我不記得這個問題。 也許您在MVC專家那里可以了解情況。

您可以使用Regex屬性將精度保留為十進制的十進制數。這還允許您在Regex失敗時添加自定義消息,例如“您的值在十進制后最多可以有9位。” 或類似的東西。 另外,如果您啟用了客戶端驗證,則Regex將在客戶端驗證和服務器端驗證中均起作用。

因此,經過幾個小時的頭部撞擊,我決定使用以下自定義模型活頁夾來獲取小數。 它確保所有十進制值在綁定它們之前都是可解析的。

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

除非有人提出了更有趣的方法,否則我會堅持下去。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM