【问题标题】:Display validation error when TimeSpan model binding exceptions occurTimeSpan 模型绑定异常时显示验证错误
【发布时间】:2013-05-04 17:34:51
【问题描述】:

在 ASP.NET MVC 4 应用程序中,我有一个视图模型,其中包含一个可为空的 TimeSpan 属性:

[DisplayName("My time")]
public TimeSpan? MyTime { get; set; }

它绑定到视图中的输入元素:

@Html.EditorFor(model => model.MyTime)

输入框在自定义编辑器模板TimeSpan.cshtml的帮助下呈现:

@model Nullable<System.TimeSpan>

@Html.TextBox("", (Model.HasValue
    ? Model.Value.ToString(@"hh\:mm") : string.Empty),
    new { @class = "text-box single-line hasTimepicker" data_timepicker = true })

现在,如果我输入以下两种无效时间并提交页面,我会得到模型绑定器的以下不同行为:

  • 如果我输入一个字母,在输入元素中说"a",当我深入到ModelState.Values 集合时,此属性的ModelErrorErrorMessage 属性设置为一条消息("The value \"a\" for \"My time\" is invalid.") 和Exception 属性为 nullMyTime 的绑定值为null

    ErrorMessage 显示在页面的验证摘要中。

  • 如果我在输入元素中输入了无效时间(例如 "25:12"),则此属性的 ModelError 会将 ErrorMessage 属性设置为空字符串,但将 Exception 属性设置为 @ 类型的异常987654340@ 带有 OverflowException 类型的内部异常,告诉我无法分析 TimeSpan,因为其中一个数字组件超出了有效范围。 MyTime 的绑定值为null

    同样,ErrorMessage 显示在页面的验证摘要中。但是因为它是空的,所以不是很有用。

理想情况下,对于无效输入的第二种情况,我希望得到与第一种情况相同的错误消息,例如"The value \"25:12\" for \"My time\" is invalid."

我该如何解决这个问题?

编辑

自定义验证属性显然在这里没有帮助,因为当模型绑定器已经检测到无效值时,不会为上述示例中的无效输入调用它。我曾尝试过这种方法但没有成功。

【问题讨论】:

    标签: asp.net asp.net-mvc validation asp.net-mvc-4 model-binding


    【解决方案1】:

    问题是错误发生在模型绑定中,这就是您需要捕获并检查它的地方。

    我有一个用于 TimeSpan? 的 Timespan 模型绑定器和编辑器模板,它应该可以满足您的需求,那就是 up on Gist

    【讨论】:

    • 创建模型绑定器(我不是很熟悉)并尝试使用您的代码的想法为我指明了正确的方向,尽管我最终做了不同的事情(请参阅我自己的答案) .我学到了一些新东西。谢谢!
    【解决方案2】:

    @Chao 的回答让我走上了使用自定义模型绑定器的正确轨道。

    因为我想尽可能多地保持默认模型绑定器的功能(输入格式的灵活性、本地化等)不变,并且只有在用户输入 "25:12" 或类似我创建了以下绑定器,它只检测默认模型绑定器是否已将OverflowException(作为内部异常)添加到模型状态,如果是,我会向状态添加错误消息:

    public class TimeSpanModelBinder : DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext,
            ModelBindingContext bindingContext)
        {
            object timeSpanValue = base.BindModel(controllerContext, bindingContext);
    
            var modelState = bindingContext.ModelState[bindingContext.ModelName];
            var hasOverflowException = modelState.Errors
                .Any(e => e.Exception != null &&
                    e.Exception.InnerException is OverflowException);
    
            if (hasOverflowException)
            {
                var rawValues = modelState.Value.RawValue as string[];
                if (rawValues != null && rawValues.Length >= 1)
                {
                    bindingContext.ModelState.AddModelError(
                        bindingContext.ModelName, string.Format(
                            "The value \"{0}\" for field \"{1}\" is invalid.",
                            rawValues[0],
                            bindingContext.ModelMetadata.GetDisplayName()));
                }
            }
    
            return timeSpanValue;
        }
    }
    

    添加到global.asax/Application_Start()ModelBinders 集合中:

    ModelBinders.Binders.Add(typeof(TimeSpan), new TimeSpanModelBinder());
    ModelBinders.Binders.Add(typeof(TimeSpan?), new TimeSpanModelBinder());
    

    【讨论】:

    • 有没有办法让这个ModelBinder 绑定AM/PM 格式?当我提交格式为 11:45 PM 的 TimeSpan 时,它仍然会抱怨
    猜你喜欢
    • 2012-09-14
    • 1970-01-01
    • 2013-08-02
    • 1970-01-01
    • 2013-01-14
    • 1970-01-01
    • 2018-02-07
    • 2012-10-09
    • 1970-01-01
    相关资源
    最近更新 更多