Dot-Net
Asp.NET MVC 2 中的通用 TimeSpan 綁定
我有一個綁定到模型的輸入表單。該模型具有 TimeSpan 屬性,但只有當我輸入時間為 hh:mm 或 hh:mm:ss 時才能正確獲取值。我想要的是它擷取值,即使它被寫為 hhmm 或 hh.mm 或 hh.mm.ss 或……我希望正確解析許多不同的格式。這可能嗎?
謝謝!
是的 - 為您的模型對象編寫自定義模型綁定器。SO上有一個關於這個主題的主題:ASP.NET MVC2 - Custom Model Binder Examples
我為 Carles 的程式碼添加了一些增強功能,並希望在這里分享它們,以防它們對其他人有用。
- 確保如果沒有模式成功解析時間,則仍然呼叫基以顯示驗證錯誤(否則該值保留為原樣
TimeSpan.Zero並且不會引發驗證錯誤。)- 使用循環而不是鍊式
ifs。- 支持使用就夠
AM了。PM- 忽略空格。
這是程式碼:
public sealed class TimeSpanModelBinder : DefaultModelBinder { private const DateTimeStyles _dateTimeStyles = DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeLocal | DateTimeStyles.NoCurrentDateDefault; protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor) { var form = controllerContext.HttpContext.Request.Form; if (propertyDescriptor.PropertyType.Equals(typeof(TimeSpan?)) || propertyDescriptor.PropertyType.Equals(typeof(TimeSpan))) { var text = form[propertyDescriptor.Name]; TimeSpan time; if (text != null && TryParseTime(text, out time)) { SetProperty(controllerContext, bindingContext, propertyDescriptor, time); return; } } // Either a different type, or we couldn't parse the string. base.BindProperty(controllerContext, bindingContext, propertyDescriptor); } public static bool TryParseTime(string text, out TimeSpan time) { if (text == null) throw new ArgumentNullException("text"); var formats = new[] { "HH:mm", "HH.mm", "HHmm", "HH,mm", "HH", "H:mm", "H.mm", "H,mm", "hh:mmtt", "hh.mmtt", "hhmmtt", "hh,mmtt", "hhtt", "h:mmtt", "h.mmtt", "hmmtt", "h,mmtt", "htt" }; text = Regex.Replace(text, "([^0-9]|^)([0-9])([0-9]{2})([^0-9]|$)", "$1$2:$3$4"); text = Regex.Replace(text, "^[0-9]$", "0$0"); foreach (var format in formats) { DateTime value; if (DateTime.TryParseExact(text, format, CultureInfo.InvariantCulture, _dateTimeStyles, out value)) { time = value.TimeOfDay; return true; } } time = TimeSpan.Zero; return false; } }這可能看起來有點過頭了,但我希望我的使用者能夠輸入幾乎任何內容並讓我的應用程序執行它。
它可以通過以下程式碼應用於所有
DateTime實例Global.asax.cs:ModelBinders.Binders.Add(typeof(TimeSpan), new TimeSpanModelBinder());或者只是在特定的操作方法參數上:
public ActionResult Save([ModelBinder(typeof(TimeSpanModelBinder))] MyModel model) { ... }這是一個簡單的單元測試,只是為了驗證一些潛在的輸入/輸出:
[TestMethod] public void TimeSpanParsing() { var testData = new[] { new { Text = "100", Time = new TimeSpan(1, 0, 0) }, new { Text = "10:00 PM", Time = new TimeSpan(22, 0, 0) }, new { Text = "2", Time = new TimeSpan(2, 0, 0) }, new { Text = "10", Time = new TimeSpan(10, 0, 0) }, new { Text = "100PM", Time = new TimeSpan(13, 0, 0) }, new { Text = "1000", Time = new TimeSpan(10, 0, 0) }, new { Text = "10:00", Time = new TimeSpan(10, 0, 0) }, new { Text = "10.00", Time = new TimeSpan(10, 0, 0) }, new { Text = "13:00", Time = new TimeSpan(13, 0, 0) }, new { Text = "13.00", Time = new TimeSpan(13, 0, 0) }, new { Text = "10 PM", Time = new TimeSpan(22, 0, 0) }, new { Text = " 10\t PM ", Time = new TimeSpan(22, 0, 0) }, new { Text = "10PM", Time = new TimeSpan(22, 0, 0) }, new { Text = "1PM", Time = new TimeSpan(13, 0, 0) }, new { Text = "1 am", Time = new TimeSpan(1, 0, 0) }, new { Text = "1 AM", Time = new TimeSpan(1, 0, 0) }, new { Text = "1 pm", Time = new TimeSpan(13, 0, 0) }, new { Text = "1 PM", Time = new TimeSpan(13, 0, 0) }, new { Text = "01 PM", Time = new TimeSpan(13, 0, 0) }, new { Text = "0100 PM", Time = new TimeSpan(13, 0, 0) }, new { Text = "01.00 PM", Time = new TimeSpan(13, 0, 0) }, new { Text = "01.00PM", Time = new TimeSpan(13, 0, 0) }, new { Text = "1:00PM", Time = new TimeSpan(13, 0, 0) }, new { Text = "1:00 PM", Time = new TimeSpan(13, 0, 0) }, new { Text = "12,34", Time = new TimeSpan(12, 34, 0) }, new { Text = "1012PM", Time = new TimeSpan(22, 12, 0) }, }; foreach (var test in testData) { try { TimeSpan time; Assert.IsTrue(TimeSpanModelBinder.TryParseTime(test.Text, out time), "Should parse {0}", test.Text); if (!Equals(time, test.Time)) Assert.Fail("Time parse failed. Expected {0} but got {1}", test.Time, time); } catch (FormatException) { Assert.Fail("Received format exception with text {0}", test.Text); } } }希望能幫助別人。