代码之家  ›  专栏  ›  技术社区  ›  Pawel Krakowiak

如何在ASP.NET MVC控制器中设置小数分隔符?

  •  20
  • Pawel Krakowiak  · 技术社区  · 15 年前

    NerdDinner 尝试自学ASP.NETMVC的应用程序。然而,我偶然发现了全球化的一个问题,我的服务器用逗号作为小数分隔符来表示浮点数,但虚拟地球地图要求浮点数带有点,这导致了一些问题。

    我已经解决了 the issue with the mapping JavaScript in my views ,但如果我现在试图发布一个编辑过的晚餐条目,并将点作为小数点分隔符,控制器将失败(抛出 InvalidOperationException )更新模型时(在 UpdateModel() OnActionExecuting() 但那没用。

    4 回复  |  直到 7 年前
        1
  •  65
  •   D.L.MAN    6 年前

    我刚刚在一个实际项目中重新讨论了这个问题,并最终找到了一个可行的解决方案。正确的解决方案是为该类型使用自定义模型活页夹 decimal (及 decimal?

    using System.Globalization;
    using System.Web.Mvc;
    
    public class DecimalModelBinder : DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            object result = null;
    
            // Don't do this here!
            // It might do bindingContext.ModelState.AddModelError
            // and there is no RemoveModelError!
            // 
            // result = base.BindModel(controllerContext, bindingContext);
    
            string modelName = bindingContext.ModelName;
            string attemptedValue = bindingContext.ValueProvider.GetValue(modelName)?.AttemptedValue;
    
            // in decimal? binding attemptedValue can be Null
            if (attemptedValue != null)
            {
                // Depending on CultureInfo, the NumberDecimalSeparator can be "," or "."
                // Both "." and "," should be accepted, but aren't.
                string wantedSeperator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator;
                string alternateSeperator = (wantedSeperator == "," ? "." : ",");
    
                if (attemptedValue.IndexOf(wantedSeperator, StringComparison.Ordinal) == -1
                    && attemptedValue.IndexOf(alternateSeperator, StringComparison.Ordinal) != -1)
                {
                    attemptedValue = attemptedValue.Replace(alternateSeperator, wantedSeperator);
                }
    
                try
                {
                    if (bindingContext.ModelMetadata.IsNullableValueType && string.IsNullOrWhiteSpace(attemptedValue))
                    {
                        return null;
                    }
    
                    result = decimal.Parse(attemptedValue, NumberStyles.Any);
                }
                catch (FormatException e)
                {
                    bindingContext.ModelState.AddModelError(modelName, e);
                }
            }
    
            return result;
        }
    }
    

    然后在应用程序_Start()中的Global.asax.cs中:

    ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
    ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());
    

    请注意,代码不是我的,我实际上是在Kristof Neirynck的博客上找到的 here . 我只是编辑了几行,正在为特定的数据类型添加活页夹,而不是替换默认活页夹。

        2
  •  6
  •   Juan Carlos Oropeza    6 年前

      <system.web>
        <globalization uiCulture="en" culture="en-US" />
    

    您似乎正在使用的服务器的设置语言使用逗号而不是小数点。您可以按照应用程序的设计方式将区域性调整为使用逗号的区域性,例如en US。

        3
  •  0
  •   Steve    15 年前

     float i = float.Parse("0.1", CultureInfo.InvariantCulture);
    

    编辑

        4
  •  0
  •   Colin Wiseman    9 年前

    我对此有不同的看法,你可能会喜欢。我不喜欢这个被接受的答案,因为它没有检查其他字符。我知道会有这样一种情况,货币符号会出现在方框中,因为我的用户不太清楚。所以是的,我可以签入javascript来删除它,但是如果出于某种原因javascript没有打开呢?然后可能会有更多的角色通过。或者如果有人试图通过传递未知字符向您发送垃圾邮件。。。谁知道呢!所以我决定用正则表达式。它稍微慢了一点,慢了一小部分——在我的例子中,1000000次正则表达式迭代只花了不到3秒的时间,而在昏迷和周期上进行字符串替换大约需要1秒。但鉴于我不知道会有什么样的角色出现,我很高兴能有这么一丁点儿的表演。

    public class DecimalModelBinder : DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext,
                                         ModelBindingContext bindingContext)
        {
            string modelName = bindingContext.ModelName;
            string attemptedValue =
                bindingContext.ValueProvider.GetValue(modelName).AttemptedValue;
    
            if (bindingContext.ModelMetadata.IsNullableValueType
                    && string.IsNullOrWhiteSpace(attemptedValue))
            {
                return null;
            }
    
            if (string.IsNullOrWhiteSpace(attemptedValue))
            {
                return decimal.Zero;
            }
    
            decimal value = decimal.Zero;
            Regex digitsOnly = new Regex(@"[^\d]", RegexOptions.Compiled);
            var numbersOnly = digitsOnly.Replace(attemptedValue, "");
            if (!string.IsNullOrWhiteSpace(numbersOnly))
            {
                var numbers = Convert.ToDecimal(numbersOnly);
                value = (numbers / 100m);
    
                return value;
            }
            else
            {
                if (bindingContext.ModelMetadata.IsNullableValueType)
                {
                    return null;
                }
    
            }
    
            return value;
        }
    }
    

    基本上,移除 全部的 非数字字符,用于非空字符串。转换成十进制。除以100。返回结果。