2013-05-04 63 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());