2010-09-30 81 views
9

में बाध्यकारी मेरे पास एक इनपुट फॉर्म है जो मॉडल से जुड़ा हुआ है। मॉडल में टाइमस्पेन प्रॉपर्टी है, लेकिन अगर मैं एचएच: एमएम या एचएच: एमएम: एसएस के रूप में समय दर्ज करता हूं तो यह केवल सही मान प्राप्त करता है। मैं चाहता हूं कि यह मूल्य कैप्चर करने के लिए है, भले ही इसे हम्म या एचएचएमएम या एचएचएमएम.एसएस या लिखा गया हो ... मैं कई अलग-अलग स्वरूपों को सही ढंग से पार्स करना चाहता हूं। क्या यह संभव है?जेएसपीसी टाइमस्पेन एएसपी.नेट एमवीसी 2

धन्यवाद!

उत्तर

4

हां - अपने मॉडल ऑब्जेक्ट के लिए कस्टम मॉडल बाइंडर लिखें। सिर्फ इतना है कि विषय के बारे में एक धागा इतने पर यहाँ नहीं है: ASP.NET MVC2 - Custom Model Binder Examples

+0

बढ़िया! यह जाने का तरीका है ... –

3

रिकॉर्ड के लिए, यहाँ है कैसे मैंने किया:

using System; 
using System.Globalization; 
using System.Web.Mvc; 

namespace Utils.ModelBinders 
{ 
    public class CustomTimeSpanModelBinder : DefaultModelBinder 
    { 
     protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor) 
     { 
      var form = controllerContext.HttpContext.Request.Form; 

      if (propertyDescriptor.PropertyType.Equals(typeof(TimeSpan?))) 
      { 
       var text = form[propertyDescriptor.Name]; 
       DateTime value; 
       if (DateTime.TryParseExact(text, "HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.None, out value)) 
         SetProperty(controllerContext,bindingContext,propertyDescriptor,value.TimeOfDay); 
       else if (DateTime.TryParseExact(text, "HH.mm", CultureInfo.InvariantCulture, DateTimeStyles.None, out value)) 
        SetProperty(controllerContext, bindingContext, propertyDescriptor, value.TimeOfDay); 
       else if (DateTime.TryParseExact(text, "HHmm", CultureInfo.InvariantCulture, DateTimeStyles.None, out value)) 
        SetProperty(controllerContext, bindingContext, propertyDescriptor, value.TimeOfDay); 
       else if (DateTime.TryParseExact(text, "HH,mm", CultureInfo.InvariantCulture, DateTimeStyles.None, out value)) 
        SetProperty(controllerContext, bindingContext, propertyDescriptor, value.TimeOfDay); 
       else if (DateTime.TryParseExact(text, "HH", CultureInfo.InvariantCulture, DateTimeStyles.None, out value)) 
        SetProperty(controllerContext, bindingContext, propertyDescriptor, value.TimeOfDay); 
      } 
      else 
      { 
       base.BindProperty(controllerContext, bindingContext, propertyDescriptor); 
      } 
     } 
    } 
} 
+0

इस कोड को साझा करने के लिए धन्यवाद। क्या आप यह भी दिखा सकते हैं कि आपने इसे इस्तेमाल करने के लिए कैसे निर्दिष्ट किया? क्या आप इसे किसी विशेष मॉडल पर केवल एक ही संपत्ति के लिए कॉन्फ़िगर कर सकते हैं, या यह सभी 'टाइमस्पैन' संपत्ति बाध्यकारी परिचालनों के लिए वैश्विक स्तर पर लागू होता है? –

+1

मैंने इसे Global_asax.cs फ़ाइल के Application_Start विधि में जोड़ा: ModelBinders.Binders.DefaultBinder = नया CustomTimeSpanModelBinder(); मुझे लगता है कि आप एनोटेशन का उपयोग करके कार्रवाई के आधार पर इसे क्रिया पर भी निर्दिष्ट कर सकते हैं। –

+1

धन्यवाद कार्ल्स। मैंने आपके कोड का एक उत्तर भी उत्तर के रूप में पोस्ट किया है। मेरे मामले में मैं कई अलग-अलग समय के तारों को संभालना चाहता था क्योंकि उचित रूप से प्रदान किया जा सकता था और व्याख्या की जा सकती थी। –

20

मैं कार्ल्स 'कोड के लिए कुछ संवर्द्धन जोड़ा गया है और मामले में उन्हें यहाँ साझा करना चाहते थे वे दूसरों के लिए उपयोगी हैं।

  • सुनिश्चित करें कि अगर कोई पैटर्न सफलतापूर्वक समय पार्स, तो अभी भी आधार के लिए एक प्रमाणीकरण त्रुटि दिखाने के लिए फोन (अन्यथा मूल्य TimeSpan.Zero रूप में छोड़ दिया जाता है और कोई सत्यापन त्रुटि उठाया।)
  • एक पाश नहीं बल्कि का उपयोग करें if एस की तुलना में।
  • 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; 
    } 
} 

यह शीर्ष पर एक छोटे से लग सकता है, लेकिन मैं अपने उपयोगकर्ताओं को काफी कुछ भी दर्ज करें और मेरे ऐप इस पर काम करने में सक्षम होना चाहता हूँ।

यह Global.asax.cs में इस कोड के माध्यम से सभी DateTime उदाहरणों के लिए लागू किया जा सकता है:

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); 
      } 
     } 
    } 

आशा है कि किसी को मदद मिलेगी।

+0

और परीक्षण के साथ भी? प्रतिभाशाली। धन्यवाद! – Ted

+0

@ टेड, आपका स्वागत है। कभी-कभी परीक्षण सबसे अच्छा दस्तावेज बनाते हैं। –

+0

कई बार, क्योंकि कई अन्य चीजों के बीच, हम आम तौर पर हमारे परीक्षणों को अद्यतित रखते हैं जबकि दस्तावेज होने की कोई गारंटी नहीं होती है। यदि परीक्षण काम करते हैं, तो "वास्तविक दस्तावेज़ीकरण" सही है। – Ted

संबंधित मुद्दे