如何在全球化 MVC 应用程序中处理十进制输入值

问题描述 投票:0回答:1

当前正在尝试重新设计 .NET 4.8 MVC 应用程序以支持全球化(需要支持英语和法语)。到目前为止,一切都很顺利。

然而,问题在于十进制输入。这是一个财务应用程序,因此处理设置为

type="number"
的输入框非常重要。严格来说,我知道值
15000,25
不被视为数字,并且不会隐式转换为小数(我在视图模型中使用的支持字段数据类型)。考虑到这一点,我有一个自定义模型活页夹:

public class DecimalModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

        if (valueProviderResult == null)
        {
            return base.BindModel(controllerContext, bindingContext);
        }

        if (string.IsNullOrEmpty(valueProviderResult.AttemptedValue))
        {
            return null;
        }

        var result = decimal.TryParse(valueProviderResult.AttemptedValue, NumberStyles.Currency, CultureInfo.InvariantCulture, out decimal covertedOutput);

        if (result)
        {
            return covertedOutput;
        }

        return null;
    }
}

然后将该模型绑定器注册到 Global.asax 文件中。上面的内容似乎在一定程度上有效......特别是在 Firefox 中,因为我可以在表单输入中输入 15000,25,而后端发生的情况是 15000.25 记录在数据库中。

这是 chrome 中的一个不同的故事,因为

  1. 我无法输入 15000,25 作为值,只能输入基于小数点的数字 和
  2. 从服务器重新加载时 - chrome 将尝试获取 15000.25 并将其解析为输入中的 15000,25...失败,并出现错误:

指定值“15000,25”无法解析,或者超出范围

我的问题是这样的 - 我应该强迫用户始终处理真正的基于十进制的数字吗?那么阻止他们输入 15000,25 但允许 15000.25 呢?还是有一种我没有看到的解决方法/最佳实践?

这是我正在使用的小数字段。表单控件和视图模型属性:

@Html.TextBoxFor(model => model.SellAmount, "{0:f2}", new {min = "0", type = "number", step = "1000" })
public decimal? SellAmount { get; set; }
c# asp.net-mvc localization number-formatting globalization
1个回答
0
投票

因此,通过进行大量研究,我设法想出了一个解决方案。

  1. 使用 type=text 而不是数字
  2. 通过扩展 MvcHtmlString 使用自定义输入

我遇到的一个问题是,浏览器会在视图重新渲染期间尝试将其自己的本地化值插入到文本框中。这会导致 chrome 引发以下错误:

指定值“{value}”无法解析,或超出范围

为了防止这种情况发生,我扩展了MVC输入控件:

  public static class InputExtensions
  {
     public static MvcHtmlString NumberInput<TModel, TProperty>(this HtmlHelper<TModel> helper
            , Expression<Func<TModel, TProperty>> expression, string format = null)
     {
        // Get decimal value from the model
        var value = (decimal)ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model;
    
        // Render the input, this stops the browser from inserting it's own 'localized' format
        helper.TextBoxFor(expression, format, new { pattern = @"[0-9]+([\.][0-9]{1,2})?", @Value = value });
     }
  }

您只需从视图中调用分机即可:

 @Html.NumberInput(model => model.Input.SellAmount, "{0:f2}")

执行上述操作意味着我可以强制用户使用 000.00 格式的小数,在其他地方,我只是让 UICulture 在显示值(在标签等中)时接管

这解决了我遇到的很多本地化问题。

© www.soinside.com 2019 - 2024. All rights reserved.