MVC 5.2.3 - 全球化 - 日期时间到带范围的十进制

MVC 5.2.3 - Globalization - DateTime & Decimal with Range

长话短说,我开始了一个使用 MVC 5.2.3(具有所有更新的 JS 框架)的新项目,期望我在 MVC 2 验证中遇到的许多问题都得到解决,我错了.

基本上,我试图为 DateTimeDecimal 提供验证,我快把自己逼疯了。
对于小数字段,在 EN 和 DE(文化)中使用浏览器,我遇到了逗号和点(小数除法)以及我设置的范围的问题。

使用 DateTime 我什至尝试了 DisplayFormat 只是为了显示日期而不是时间,无论如何 day/month/year 的顺序与 ./- 只是失败。

示例:

同样适用于日期时间显示格式和类似的 JS 验证....

分享一下我目前的情况:

测试对象

public class TestObject
{       
    ....
    [Display(Name = "D2", ResourceType = typeof(WebApplication1.Models.Res.TestObject))]
    [Range(0, 999.9999)]
    public decimal? D1 { get; set; }
    // On DBContext I have defined the range/precision
    // modelBuilder.Entity<TestObject>().Property(x => x.D2).HasPrecision(7, 4);

    [Display(Name = "Date1", ResourceType = typeof(WebApplication1.Models.Res.TestObject))]
    //[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = @"{0:dd\/MM\/yyyy}")]
    public DateTime Date1 { get; set; }
    ....
}

view.cshtml

<div class="form-group">
            @Html.LabelFor(model => model.D2, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.D2, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.D2, "", new { @class = "text-danger" })
            </div>
        </div>
 <div class="form-group">
            @Html.LabelFor(model => model.Date1, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Date1, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Date1, "", new { @class = "text-danger" })
            </div>
        </div>

_layout.cshtml

    <script src="~/Scripts/globalize/globalize.js" type="text/javascript"></script></script>
    <script src="~/Scripts/globalize/cultures/globalize.culture.de.js" type="text/javascript"></script>
    <script src="~/Scripts/globalize/cultures/globalize.culture.en-US.js" type="text/javascript"></script>  

    <script>
  $.validator.methods.number = function (value, element) {
    return this.optional(element) ||
        !isNaN(Globalize.parseFloat(value));
  }

  $.validator.methods.date = function (value, element) {
    return this.optional(element) ||
        Globalize.parseDate(value);
  }

  $(document).ready(function () {
    Globalize.culture('@System.Threading.Thread.CurrentThread.CurrentCulture');
  });
</script>

DecimalModelBinder

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;

    // 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) == -1
        && attemptedValue.IndexOf(alternateSeperator) != -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;
}

}

Global.asax

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ...
        ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder());
        ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder());
       ...
    }

    private void Application_BeginRequest(Object source, EventArgs e)
    {
        HttpApplication application = (HttpApplication)source;
        HttpContext context = application.Context;

        string culture = null;
        if (context.Request.UserLanguages != null && Request.UserLanguages.Length > 0)
        {
            culture = Request.UserLanguages[0];
            Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(culture);
            Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
        }
    }
}

web.config

    <globalization culture="auto" uiCulture="auto" enableClientBasedCulture="true" />

根据错误消息,我看到您正确显示了数据,但没有正确解析它。

我认为问题出在这里:

$.validator.methods.number = function (value, element) {
    return this.optional(element) ||
        !isNaN(Globalize.parseFloat(value));
}

在这里看不到文化用法,可能是某些 classes 没有正确的文化。根据标准。 999,999 在德语中代表 999 999 - 精度部分没有任何数字的大整数。检查 javascript 的输入并尝试调试它。

首先,enableClientBasedCulture 当前未使用 (MSDN)。看起来您的全球化 class 总是被设置为 ENG 文化,即使您在 document.ready 事件中执行了明确的 all。尝试在 web.config 中明确设置德国文化并检查您的逻辑。它应该适用于 DE 但不适用于 EN。如果是这样,那么您每次尝试解析数据时都应该提供正确的文化。

但是,如果不是,则问题不在全球化中。

看来我还需要创建自己的范围方法..... 现在好像可以用了。

$.validator.methods.range = function(value, element, param) {
    console.log('----------------');
    console.log(value);
    console.log(element);                
    var globalizedValue = value.replace(",", ".");
    console.log(param[0]);
    var globalizedValueParam0 = param[0];
    console.log(param[1]);
    var globalizedValueParam1 = param[1];        
    console.log(globalizedValueParam0);
    console.log(globalizedValueParam1);

    //return this.optional(element) || (globalizedValue >= param[0] && globalizedValue <= param[1]);
    return this.optional(element) || (globalizedValue >= globalizedValueParam0 && globalizedValue <= globalizedValueParam1);
};