6

के बीच पैरामीटर और मान्यता राज्य बनी रहती है जब मैं डिफ़ॉल्ट मॉडल एक जटिल वस्तु जो एक कार्रवाई के लिए एक पैरामीटर है प्रपत्र मापदंडों बाध्य करने के लिए बाध्यकारी उपयोग करते हैं, ढांचा मूल्यों के लिए पारित किया याद है पहला अनुरोध, जिसका अर्थ है कि उस कार्रवाई के बाद के किसी भी अनुरोध को पहले के समान डेटा मिलता है। पैरामीटर मान और सत्यापन स्थिति असंबद्ध वेब अनुरोधों के बीच बनी हुई है।ASP.NET MVC बीटा 1: DefaultModelBinder को गलत तरीके से असंबंधित अनुरोध

यहाँ मेरी नियंत्रक कोड है (service एप्लिकेशन के पिछले सिरे पर करने के लिए उपयोग का प्रतिनिधित्व करता है):

[AcceptVerbs(HttpVerbs.Get)] 
    public ActionResult Create() 
    { 
     return View(RunTime.Default); 
    } 

    [AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult Create(RunTime newRunTime) 
    { 
     if (ModelState.IsValid) 
     { 
      service.CreateNewRun(newRunTime); 
      TempData["Message"] = "New run created"; 
      return RedirectToAction("index"); 
     } 
     return View(newRunTime); 
    } 

मेरे .aspx (दृढ़ता से ViewPage<RunTime के रूप में आपके द्वारा लिखा गया>) दृश्य की तरह निर्देशों में शामिल हैं:

<%= Html.TextBox("newRunTime.Time", ViewData.Model.Time) %> 

यह DefaultModelBinder वर्ग है, जो meant to autobind my model's properties है उपयोग करता है।

मैं पेज मारा, मान्य डेटा दर्ज करें (उदा समय = 1)। ऐप सही समय = 1 के साथ नई वस्तु को बचाता है। फिर मैं इसे फिर से दबाता हूं, अलग-अलग मान्य डेटा दर्ज करता हूं (उदा। समय = 2)। हालांकि सहेजा गया डेटा मूल है (उदा। समय = 1)। यह सत्यापन को भी प्रभावित करता है, इसलिए यदि मेरा मूल डेटा अमान्य था, तो भविष्य में दर्ज किए गए सभी डेटा को अमान्य माना जाता है। आईआईएस को पुनरारंभ करना या मेरे कोड को पुनर्निर्माण करना लगातार स्थिति को फहराता है।

मैं अपने खुद के हार्ड-कोडेड मॉडल बांधने की मशीन, एक बुनियादी अनुभवहीन उदाहरण जिनमें से नीचे दिखाया गया है लिख कर इस समस्या को ठीक कर सकते हैं।

[AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult Create([ModelBinder(typeof (RunTimeBinder))] RunTime newRunTime) 
    { 
     if (ModelState.IsValid) 
     { 
      service.CreateNewRun(newRunTime); 
      TempData["Message"] = "New run created"; 
      return RedirectToAction("index"); 
     } 
     return View(newRunTime); 
    } 


internal class RunTimeBinder : DefaultModelBinder 
{ 
    public override ModelBinderResult BindModel(ModelBindingContext bindingContext) 
    { 
     // Without this line, failed validation state persists between requests 
     bindingContext.ModelState.Clear(); 


     double time = 0; 
     try 
     { 
      time = Convert.ToDouble(bindingContext.HttpContext.Request[bindingContext.ModelName + ".Time"]); 
     } 
     catch (FormatException) 
     { 
      bindingContext.ModelState.AddModelError(bindingContext.ModelName + ".Time", bindingContext.HttpContext.Request[bindingContext.ModelName + ".Time"] + "is not a valid number"); 
     } 

     var model = new RunTime(time); 
     return new ModelBinderResult(model); 
    } 
} 

क्या मुझे कुछ याद आ रही है? मुझे नहीं लगता कि यह एक ब्राउज़र सत्र समस्या है क्योंकि यदि समस्या एक ब्राउज़र में दर्ज की गई है और दूसरे में दूसरा डेटा दर्ज किया गया है तो मैं समस्या को पुन: उत्पन्न कर सकता हूं।

उत्तर

5

यह पता चला है कि समस्या यह थी कि मेरे नियंत्रकों को कॉल के बीच पुन: उपयोग किया जा रहा था। मेरे मूल पोस्ट से निकलने के लिए मैंने जो विवरण चुना है, वह यह है कि मैं अपने नियंत्रकों को बनाने के लिए Castle.Windsor कंटेनर का उपयोग कर रहा हूं। मैं अपने नियंत्रक को क्षणिक जीवन शैली के साथ चिह्नित करने में विफल रहा था, इसलिए मुझे प्रत्येक अनुरोध पर एक ही उदाहरण मिल रहा था। इस प्रकार बाइंडर द्वारा उपयोग किए जाने वाले संदर्भ का पुन: उपयोग किया जा रहा था और निश्चित रूप से इसमें स्थिर डेटा शामिल था।

मैंने ईलॉन के कोड और खान के बीच अंतर का सावधानीपूर्वक विश्लेषण करते हुए समस्या की खोज की, अन्य सभी संभावनाओं को खत्म कर दिया। Castle documentation says के रूप में, यह एक "भयानक गलती" है! दूसरों को चेतावनी दीजिए!

आपकी प्रतिक्रिया के लिए धन्यवाद Eilon - अपना समय लेने के लिए खेद है।

+0

यह सटीक बात मेरे साथ पहले हुई है। इसे समझने में मुझे काफी समय लगा। भविष्य में, एमवीसीकंट्रिब को अपने विंडसर कॉन्टैनेर एक्सटेंशन विधियों का उपयोग करके अपने नियंत्रकों को पंजीकृत करने दें। –

+0

अच्छी नोक - धन्यवाद बेन। आपको वोट प्राप्त करने और हरे रंग की टिक प्राप्त करने के लिए टिप्पणी के बजाय इसे उत्तर के रूप में रखना चाहिए था! –

+0

धन्यवाद एलेक्स, मैं दोपहर के अधिकांश दिनों के लिए इस सटीक समस्या के खिलाफ अपना सिर मार रहा हूं। –

2

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

सार्वजनिक वर्ग HomeController:

यहाँ मेरी नियंत्रक है नियंत्रक { public ActionResult सूचकांक() { ViewData [ "शीर्षक"] = "मुख पृष्ठ"; स्ट्रिंग संदेश = "स्वागत है:" + टेम्पडडाटा ["संदेश"]; यदि (TempData.ContainsKey ("मान")) { int theValue = (int) TempData ["value"]; संदेश + = "" + theValue.ToString(); } व्यूडाटा ["संदेश"] = संदेश; वापसी देखें(); इसके अलावा

<% using (Html.BeginForm()) { %> 
<%= Html.TextBox("newRunTime.TheValue", ViewData.Model.TheValue) %> 
<input type="submit" value="Save" /> 
<% } %> 

, मुझे यकीन है कि क्या "क्रम" प्रकार की तरह देखा नहीं था, इसलिए मैं बना दिया: }

[AcceptVerbs(HttpVerbs.Get)] 
public ActionResult Create() { 
    return View(RunTime.Default); 
} 

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Create(RunTime newRunTime) { 
    if (ModelState.IsValid) { 
     //service.CreateNewRun(newRunTime); 
     TempData["Message"] = "New run created"; 
     TempData["value"] = newRunTime.TheValue; 
     return RedirectToAction("index"); 
    } 
    return View(newRunTime); 
} 

}

और यहाँ मेरी देखें (Create.aspx) है यह एक:

public class RunTime { 
     public static readonly RunTime Default = new RunTime(-1); 

     public RunTime() { 
     } 

     public RunTime(int theValue) { 
      TheValue = theValue; 
     } 

     public int TheValue { 
      get; 
      set; 
     } 
    } 

क्या यह संभव है कि रनटाइम के आपके कार्यान्वयन में कुछ स्थिर मूल्य शामिल हों या कुछ और?

धन्यवाद,

Eilon

2

मुझे यकीन है कि अगर यह या संबंधित नहीं है, लेकिन है नहीं कर रहा हूँ, <% = Html.TextBox ("newRunTime.Time" करने के लिए ViewData.Model.Time अपने कॉल)%> वास्तव में जांच की जा रही गाया एचटीएमएल आपको बता दूँगी अगर यह हो रहा है गलत अधिभार को चुन सकते हैं (क्योंकि समय एक पूर्णांक है, यह string value से object htmlAttributes अधिभार लेने, बल्कि होगा।

ViewData.Model.Time.ToString() को पूर्णांक बदल रहा होगा मजबूर करें सही अधिभार।

ऐसा लगता है कि आपकी समस्या कुछ अलग है, लेकिन मैंने देखा कि अतीत में जला दिया गया है।

+0

सुझाव बेन के लिए धन्यवाद। यह इस समय समस्या नहीं है, लेकिन ऐसा लगता है कि मुझे भविष्य के बारे में पता होना चाहिए, इसलिए इसे मेरे ध्यान में लाने के लिए धन्यवाद। –

0

सेब, मुझे यकीन नहीं है कि आप एक उदाहरण से क्या मतलब रखते हैं। मैं एकता विन्यास के बारे में कुछ भी नहीं जानता। मैं Castle.Windsor के साथ स्थिति की व्याख्या करूंगा और शायद यह आपको एकता को सही तरीके से कॉन्फ़िगर करने में मदद करेगा।

डिफ़ॉल्ट रूप से, Castle.Windsor प्रत्येक बार दिए गए प्रकार का अनुरोध करने पर एक ही ऑब्जेक्ट देता है। यह सिंगलटन जीवनशैली है। Castle.Windsor documentation में विभिन्न जीवनशैली विकल्पों का एक अच्छा स्पष्टीकरण है।

एएसपी.नेट एमवीसी में, नियंत्रक वर्ग का प्रत्येक उदाहरण उस वेब अनुरोध के संदर्भ में है जो इसे सेवा के लिए बनाया गया था। इसलिए यदि आपका आईओसी कंटेनर हर बार आपके कंट्रोलर क्लास का एक ही उदाहरण देता है, तो आपको हमेशा उस नियंत्रक वर्ग का उपयोग करने वाले पहले वेब अनुरोध के संदर्भ में एक नियंत्रक मिल जाएगा। विशेष रूप से, ModelState और DefaultModelBinder द्वारा उपयोग की जाने वाली अन्य वस्तुओं का पुन: उपयोग किया जाएगा, इसलिए ModelState में आपके बाध्य मॉडल ऑब्जेक्ट और सत्यापन संदेश बाले होंगे।

इसलिए जब भी एमवीसी आपके नियंत्रक वर्ग के उदाहरण का अनुरोध करता है तो आपको एक नया उदाहरण वापस करने के लिए अपने आईओसी की आवश्यकता होती है।

कैसल में। विन्डसर, इसे क्षणिक जीवनशैली कहा जाता है। इसे कॉन्फ़िगर करने के लिए, आपके पास दो विकल्प हैं:

  1. एक्सएमएल कॉन्फ़िगरेशन: आप अपनी कॉन्फ़िगरेशन फ़ाइल में प्रत्येक तत्व को lifestlye = "क्षणिक" जोड़ते हैं जो नियंत्रक का प्रतिनिधित्व करता है।
  2. इन-कोड कॉन्फ़िगरेशन: जब आप नियंत्रक को पंजीकृत करते हैं तो आप क्षणिक जीवनशैली का उपयोग करने के लिए कंटेनर को बता सकते हैं। यह एमवीसी कॉन्ट्रिब सहायक है जो बेन ने आपके लिए स्वचालित रूप से उल्लेख किया है - MvcContrib source code में रजिस्टर नियंत्रक विधि को देखें।

मुझे कल्पना होगी कि यूनिटी कैसल में जीवनशैली के लिए एक समान अवधारणा प्रदान करती है। विन्डसर, तो आपको अपने नियंत्रकों के लिए क्षणिक जीवन शैली के बराबर उपयोग करने के लिए एकता को कॉन्फ़िगर करने की आवश्यकता होगी। MvcContrib में कुछ Unity support प्रतीत होता है - शायद आप वहां देख सकते हैं।

उम्मीद है कि इससे मदद मिलती है।

0

एएसपी.नेट एमवीसी ऐप में विंडसर आईओसी कंटेनर का उपयोग करने का प्रयास करते समय इसी तरह की समस्याओं को पूरा करने के बाद मुझे इसे काम करने के लिए खोज की एक ही यात्रा के माध्यम से जाना पड़ा। यहां कुछ विवरण दिए गए हैं जो किसी और की मदद कर सकते हैं।

का उपयोग करते हुए इस Global.asax में प्रारंभिक सेटअप है:

if (_container == null) 
    { 
    _container = new WindsorContainer("config/castle.config"); 
    ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(Container)); 
    } 

और जब एक नियंत्रक उदाहरण के लिए पूछा एक WindsorControllerFactory जो का उपयोग कर करता है:

return (IController)_container.Resolve(controllerType); 

जबकि विंडसर सही ढंग से सब को जोड़ने था नियंत्रकों के, कुछ कारणों से पैरामीटर को प्रासंगिक नियंत्रक कार्रवाई में पास नहीं किया जा रहा था। इसके बजाय वे सभी शून्य थे, हालांकि यह सही कार्रवाई को बुला रहा था।

डिफ़ॉल्ट कंटेनर वापस एकमात्र, नियंत्रकों के लिए स्पष्ट रूप से एक बुरी बात और समस्या का कारण पारित करने के लिए के लिए है:

http://www.castleproject.org/monorail/documentation/trunk/integration/windsor.html

हालांकि प्रलेखन का कहना है कि नियंत्रकों की जीवन शैली कर सकते हैं क्षणिक में बदला जा सकता है, हालांकि यह वास्तव में आपको यह नहीं बताता कि अगर आप कॉन्फ़िगरेशन फ़ाइल का उपयोग कर रहे हैं तो ऐसा कैसे करें। पता चला है यह आसान करने के लिए पर्याप्त है:

<component 
    id="home.controller" 
    type="DoYourStuff.Controllers.HomeController, DoYourStuff" 
    lifestyle="transient" /> 

और यह अब अपेक्षा के अनुरूप (अर्थात अद्वितीय नियंत्रक कंटेनर का एक उदाहरण द्वारा प्रदान की हर बार) काम करना चाहिए के बिना किसी भी कोड बदल जाता है। फिर आप अपने सभी आईओसी कॉन्फ़िगरेशन को कॉन्फ़िगरेशन फ़ाइल में कर सकते हैं जैसे कि अच्छे लड़के/लड़की जैसे कोड जो मैं जानता हूं।

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