2009-04-27 14 views
18

मैं NerdDinner एप्लिकेशन के साथ काम कर रहा हूं जो खुद को एएसपी.नेट एमवीसी सिखाने की कोशिश कर रहा है। हालांकि, मैंने वैश्वीकरण के साथ एक समस्या पर ठोकर खाई है, जहां मेरा सर्वर फ्लोटिंग पॉइंट नंबर को अल्पविरामक के रूप में अल्पविराम के साथ प्रस्तुत करता है, लेकिन वर्चुअल अर्थ मानचित्र के लिए उन्हें बिंदुओं की आवश्यकता होती है, जिससे कुछ समस्याएं होती हैं।एएसपी.नेट एमवीसी नियंत्रकों में दशमलव विभाजक कैसे सेट करें?

मैं पहले से ही the issue with the mapping JavaScript in my views समाधान कर लिया है, लेकिन अगर मैं अब दशमलव विभाजक नियंत्रक विफल रहता है के रूप में डॉट्स के साथ एक संपादित रात के खाने के प्रवेश पोस्ट करने की कोशिश (InvalidOperationException फेंक) जब मॉडल (UpdateModel() metod में) को अद्यतन करने। मुझे लगता है कि मुझे कंट्रोलर में कहीं भी उचित संस्कृति सेट करनी होगी, मैंने इसे OnActionExecuting() में आजमाया लेकिन इससे मदद नहीं मिली।

उत्तर

54

मैंने इस मुद्दे को एक वास्तविक परियोजना में फिर से संशोधित किया है और अंत में एक कार्य समाधान मिला है।

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

public class DecimalModelBinder : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, 
            ModelBindingContext bindingContext) 
    { 
     object result = null; 

     // Don't do this here! 
     // It might do bindingContext.ModelState.AddModelError 
     // and there is no RemoveModelError! 
     // 
     // result = base.BindModel(controllerContext, bindingContext); 

     string modelName = bindingContext.ModelName; 
     string attemptedValue = 
      bindingContext.ValueProvider.GetValue(modelName).AttemptedValue; 

     // Depending on CultureInfo, the NumberDecimalSeparator can be "," or "." 
     // Both "." and "," should be accepted, but aren't. 
     string wantedSeperator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator; 
     string alternateSeperator = (wantedSeperator == "," ? "." : ","); 

     if (attemptedValue.IndexOf(wantedSeperator) == -1 
      && attemptedValue.IndexOf(alternateSeperator) != -1) 
     { 
      attemptedValue = 
       attemptedValue.Replace(alternateSeperator, wantedSeperator); 
     } 

     try 
     { 
      if (bindingContext.ModelMetadata.IsNullableValueType 
       && string.IsNullOrWhiteSpace(attemptedValue)) 
      { 
       return null; 
      } 

      result = decimal.Parse(attemptedValue, NumberStyles.Any); 
     } 
     catch (FormatException e) 
     { 
      bindingContext.ModelState.AddModelError(modelName, e); 
     } 

     return result; 
    } 
} 
फिर Global.asax.cs में Application_Start में

():

ModelBinders.Binders.Add(typeof(decimal), new DecimalModelBinder()); 
ModelBinders.Binders.Add(typeof(decimal?), new DecimalModelBinder()); 

उचित समाधान प्रकार decimal (और decimal? यदि आप उन्हें प्रयोग कर रहे हैं) के लिए एक कस्टम मॉडल बांधने की मशीन है ध्यान दें कि कोड मेरा नहीं है, मैं वास्तव में इसे क्रिस्टोफ नीरिनक के ब्लॉग here पर मिला। मैंने बस कुछ पंक्तियों को संपादित किया है और एक विशिष्ट डेटा प्रकार के लिए बाइंडर जोड़ रहा हूं, डिफ़ॉल्ट बाइंडर को प्रतिस्थापित नहीं कर रहा हूं।

+2

मैंने अपने जवाब को कोड में एक अतिरिक्त चेक जोड़ने के लिए अद्यतन किया है ताकि इसे ठीक से संगत गुणों को संभाल सकें। मैंने पाया कि यदि इसे प्रयास किए गए मान के रूप में एक खाली स्ट्रिंग मिली तो यह एक अपवाद फेंक देगा भले ही संपत्ति बंधी जा सके। अब यह ठीक काम करना चाहिए। –

+1

एक पूरक क्लाइंट साइड फिक्स है जिसे इस के साथ लागू किया जाना चाहिए। आप इसे यहाँ मिल जाएगा: http://stackoverflow.com/a/8102159/41420 –

+0

स्ट्रिंग इनपुट – Furtiro

4

सेट यह आपके web.config में

<globalization uiCulture="en" culture="en-US" /> 

आप एक सर्वर है कि अल्पविराम के बजाय दशमलव स्थानों के उपयोग करने वाली भाषाओं के साथ सेटअप प्रयोग कर रहे हैं। आप उस संस्कृति को समायोजित कर सकते हैं जो अल्पविराम का उपयोग इस तरह से करता है कि आपका एप्लिकेशन डिज़ाइन किया गया है, जैसे एन-यूएस।

+1

मेरे पास पहले से ही यह है, किसी कारण से यह काम नहीं करता है। –

+0

आपके एएसपीएक्स पेज में हेडर के बारे में क्या? क्या उनमें से किसी के पास संस्कृति के लिए कुछ भी सेट है? –

+0

@ निक: नहीं, वहां कोई कस्टम सामान नहीं है। –

0

क्या आप इनवेरिएंट संस्कृति का उपयोग कर पाठ को पार्स कर सकते हैं - क्षमा करें, मेरे पास मेरे लिए नेडरडिनर कोड नहीं है, लेकिन यदि आप पार्सिंग की तुलना में डॉट-पृथक दशमलव में गुजर रहे हैं तो ठीक है अगर आप इसे बताते हैं invariant संस्कृति का उपयोग करें। जैसे

float i = float.Parse("0.1", CultureInfo.InvariantCulture); 

संपादित। मुझे संदेह है कि यह आपकी पिछली समस्या के समान ही, NerdDinner कोड में एक बग है।

+0

नहीं, मैं किसी भी संपत्ति को छू नहीं रहा हूं। यह UpdateModel() में "जादुई रूप से" होने वाला माना जाता है, लेकिन यह विवरण के बिना एक बहुत उपयोगी अपवाद फेंकता है। दो समस्याएं हैं - मॉडल से डेटा पेश करते समय मुझे डॉट्स की आवश्यकता होती है, क्योंकि जेए मैपिंग मैप टूट जाएगा, हालांकि मॉडल में डेटा वापस डालने पर मुझे इस बार कॉमा की आवश्यकता होती है, क्योंकि अन्यथा नियंत्रक टूट जाता है। यह सब थोड़ा अजीब है और मुझे यकीन नहीं है कि इसे कैसे हल किया जाए, Google ने मदद नहीं की, न तो SO किया। :( –

+0

हाँ, मुझे नहीं लगता कि कोड को बदले बिना आप इसे हल कर सकते हैं। मैं एन डी कोड है और मैं कुछ समय एक बार देख ले और यह सत्यापित करने और अगर मैं यह कर सकते हैं आप एक ठीक भेजने की कोशिश करता हूँ, लेकिन मैं कर रहा हूँ डर यह जल्द ही एक :-) –

+0

ठीक काम करना है के रूप में नहीं होगा, मैं तुम्हें परिवर्तन आप अपने अन्य सवाल में किए गए पूर्ववत करने की आवश्यकता है, मैं समस्या को ठीक करने और hopefuly मेरी ठीक कर देंगे पर वहाँ एक सुझाव पोस्ट किया है लगता है आप यहां देख रहे दुष्प्रभाव का कारण नहीं बनाते हैं। –

0

मेरे पास इस पर एक अलग लेना है, आपको यह पसंद हो सकता है। स्वीकार्य उत्तर के बारे में मुझे क्या पसंद नहीं है यह अन्य पात्रों की जांच नहीं करता है। मुझे पता है कि एक ऐसा मामला होगा जहां मुद्रा प्रतीक बॉक्स में होगा क्योंकि मेरा उपयोगकर्ता बेहतर नहीं जानता है। तो हाँ, मैं इसे हटाने के लिए जावास्क्रिप्ट में जांच सकता हूं, लेकिन अगर किसी कारण से जावास्क्रिप्ट चालू नहीं है? फिर अतिरिक्त पात्रों के माध्यम से हो सकता है। या अगर कोई स्पैम करने का प्रयास करता है तो आप अज्ञात पात्रों को पार करते हैं ... कौन जानता है! तो मैंने एक रेगेक्स का उपयोग करने का फैसला किया। यह थोड़ा धीमा, छोटा अंश धीमा है - मेरे मामले में यह रेगेक्स के 1,000,000 पुनरावृत्तियों को केवल 3 सेकंड के भीतर लिया गया था, जबकि एक कोमा और अवधि पर स्ट्रिंग करने के लिए लगभग 1 सेकंड था। लेकिन देखकर मुझे नहीं पता कि कौन से पात्र आ सकते हैं, फिर मैं इस प्रदर्शन के कुछ हद तक खुश हूं।

public class DecimalModelBinder : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, 
            ModelBindingContext bindingContext) 
    { 
     string modelName = bindingContext.ModelName; 
     string attemptedValue = 
      bindingContext.ValueProvider.GetValue(modelName).AttemptedValue; 

     if (bindingContext.ModelMetadata.IsNullableValueType 
       && string.IsNullOrWhiteSpace(attemptedValue)) 
     { 
      return null; 
     } 

     if (string.IsNullOrWhiteSpace(attemptedValue)) 
     { 
      return decimal.Zero; 
     } 

     decimal value = decimal.Zero; 
     Regex digitsOnly = new Regex(@"[^\d]", RegexOptions.Compiled); 
     var numbersOnly = digitsOnly.Replace(attemptedValue, ""); 
     if (!string.IsNullOrWhiteSpace(numbersOnly)) 
     { 
      var numbers = Convert.ToDecimal(numbersOnly); 
      value = (numbers/100m); 

      return value; 
     } 
     else 
     { 
      if (bindingContext.ModelMetadata.IsNullableValueType) 
      { 
       return null; 
      } 

     } 

     return value; 
    } 
} 

असल में,, सभी अक्षर हैं जो अंक नहीं हैं को दूर एक स्ट्रिंग है खाली नहीं है के लिए। दशमलव में कनवर्ट करें। 100 से विभाजित करें। वापसी का परिणाम।

मेरे लिए काम करता है।

+1

इस कुछ उदाहरणों में अच्छी तरह से काम करता है, अगर दशमलव कोई .00 है (अर्थात वहाँ जावास्क्रिप्ट सत्यापन या कुछ और है कि यह स्ट्रिप्स बाहर है), 100 तकनीक द्वारा विभाजित काम नहीं करता। – Ben

+0

हां। मैंने देखा है कि कुछ परिस्थितियों में, और फिर सुनिश्चित किया कि पोस्ट करने से पहले मेरा कोड हमेशा जावास्क्रिप्ट के माध्यम से दशमलव स्थान जोड़ता है। लेकिन वास्तविक जीवन में आप हमेशा ऐसा होने की उम्मीद नहीं कर सकते हैं। –

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