2013-05-04 68 views
0

在ASP.NET MVC 4应用我有一个包含一个可为空TimeSpan属性视图模型:显示验证错误时时间跨度模型结合发生异常

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

它被绑定到视图的输入元件:

@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 }) 
012:

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

输入框获取具有自定义编辑模板TimeSpan.cshtml的帮助下呈现

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

  • 如果我输入一个字母,说"a"到输入元素ModelError对于此属性,当我钻入ModelState.Values集合时,已将ErrorMessage属性设置为消息("The value \"a\" for \"My time\" is invalid."),而Exception属性为nullMyTime的界限值为null

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

  • 如果我输入无效的时间,说"25:12",到输入元素ModelError该物业有ErrorMessage属性设置为空字符串,但Exception属性设置为InvalidOperationException类型的异常类型的内部异常OverflowException告诉我TimeSpan无法分析,因为它的一个数字组件超出了有效范围。 MyTime的界限值为null

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

在理想情况下为无效的输入的第二种情况下我宁愿具有相同的种类等对第一种情况下的错误消息,例如"The value \"25:12\" for \"My time\" is invalid."

我该如何解决这个问题?

编辑

自定义验证属性显然不帮助,因为它不要求时的实例已经模型绑定检测无效值以上无效的输入。我曾尝试过这种方法,但没有成功。

回答

2

的问题是,错误是在模型发生结合,这就是你需要进行捕捉和检查它。

我有TimeSpan?一个时间跨度模型绑定和编辑模板应该做你所需要的那up on Gist

+0

创建一个模型联编程序(我不太熟悉)并尝试使用代码的想法指出了我正确的方向,尽管我最终采用了不同的方式(请参阅我自己的答案)。我学到了一些新东西。谢谢! – Slauma 2013-05-10 18:06:24

0

不完全相信,如果这是你在找什么,但这个问题可能会有所帮助: Client side validation of a timespan on asp.net mvc 3

+0

这将无济于事,因为我的问题中无效输入的定制验证属性永远不会被调用(服务器端)。我已经尝试过了。模型联编程序说它是无效的,并且在验证属性被处理之前。在情况1中,它很好。案例2(发生异常)是我的问题。 – Slauma 2013-05-04 18:03:50

1

@超的回答给我带来了使用自定义的模型绑定在正确的轨道上。

因为我希望尽可能保持默认模型联编程序(输入格式,本地化等的灵活性)的功能不变,并且在用户输入"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());