2013-03-22 11 views
5

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

[HttpGet] 
void Index() 
{ 
    return View(); 
} 

[HttpGet] 
void Index() 
{ 
    var messages = new MessageCollection(); 
    messages.AddError("Uh oh!"); 

    return View(messages); 
} 

कहाँ पाइप लाइन में मैं ViewBag की तरह एक संपत्ति कस्टम और दृढ़ता से टाइप किया है कि जोड़ने, लेकिन यह सुंदर ढंग से नियंत्रक में देखें अवगत कराया है और यह भी होता है। जब मैं एक विशिष्ट ViewModel हर समय की जरूरत नहीं है मैं नहीं बल्कि ऐसा करने चाहता हूँ ...

[HttpGet] 
void Index() 
{ 
    Messages.AddError("Uh oh!"); 

    return View(); 
} 

और दृश्य पक्ष पर, @ ((IMessageCollection) ViewBag.Messages) .Errors आईडी के बजाय बजाय है @ संदेश जैसे कुछ। एंटर जो दृढ़ता से टाइप किए जाते हैं और हर जगह उपलब्ध होते हैं। इसके अलावा, मैं अपने रेजर व्यू के शीर्ष पर कोड कोड में इसे बाहर नहीं करना चाहता हूं।

वेबफॉर्म में, मैंने ऐसा कुछ किया होगा जैसे कि इसे एक मूल पृष्ठ डालें और फिर उपयोगकर्ता नियंत्रक हो जो आवश्यकतानुसार पृष्ठों पर छुपा या दिखाया जा सके। कंट्रोलर दृश्य से decoupled के साथ, मुझे यकीन नहीं है कि समान व्यवहार को दोहराने के लिए कैसे।

क्या यह संभव है या सबसे अच्छा डिजाइन दृष्टिकोण क्या है?

धन्यवाद, स्कॉट

+0

आपके पास वास्तव में 2 विकल्प हैं: ViewBag और आपके मॉडल में एक समर्पित संपत्ति –

उत्तर

8

उस्तरा विचारों काफी साधारण है। आप एक मॉडल के साथ बातचीत करते हैं, जो दृढ़ता से टाइप किया जाता है। जो भी आप दृढ़ता से अपने विचार में टाइप करना चाहते हैं, उसके बाद, आपके मॉडल पर होना चाहिए। यदि आपके पास ऐसा कुछ है जो आप अपने मॉडल पर नहीं चाहते हैं या यह एक-ऑफ है, तो ViewBag सभी गैर-मॉडल डेटा के लिए सामान्य कैच-सब के रूप में प्रदान किया जाता है, यही कारण है कि यह गतिशील है। दृढ़ता से टाइप करने के लिए इसे पकड़ने की क्षमता सीमित होगी।

लघु और सरल: यदि आप दृढ़ता से टाइप करना चाहते हैं तो अपने दृश्य मॉडल में संदेश जोड़ें। अन्यथा, ViewBag के साथ चिपके रहें। वे आपके विकल्प हैं।

+0

ग्रेट स्पष्टीकरण! – ledgeJumper

+0

हाँ, मुझे लगता है कि यह शायद सबसे अच्छी सलाह है कि मैं इस प्रश्न का पालन करने वाले दूसरे को भी देख रहा हूं।मैं वास्तव में यह देखने के लिए देख रहा था कि क्या एमवीसी आर्किटेक्चर में कुछ ऐसा था जो इसे अपने आप को पकड़ने के लिए बढ़ाया गया था, जहां आप जानते हैं कि वे लगातार क्या करेंगे। धन्यवाद! – Scott

+0

ध्यान रखें कि कम से कम एमवीसी 5 (संभावित रूप से एमवीसी 6/कोर भी) व्यूबैग (उदा। व्यूबैग टिटल) की किसी भी प्रॉपर्टी को प्राप्त/सेट करने से फ्रेमवर्क के लिए एक अपवाद आंतरिक होता है जो उचित रूप से दबाया जाता है और उचित तरीके से संभाला जाता है। आप इसे 'बस मेरा कोड' विकल्प अक्षम करके देख सकते हैं। यह 'गतिशील' कार्यान्वयन के डिजाइन के लिए निहित है और हालांकि "यह काम करता है" यातायात-केंद्रित वेबसाइटों में उच्च प्रदर्शन प्राप्त करने के लिए यह एक गंभीर बाधा है। विचार के लिए अधिक भोजन: http://mvolo.com/fix-the-3-high-cpu-performance-problems-for-iis-aspnet-apps/ – xDisruptor

1

मैं क्रिस के जवाब से सहमत हूं और व्यक्तिगत रूप से मैं इसे व्यूबैग में फेंक दूंगा।

लेकिन अभी शैतानों अधिवक्ता खेलने के लिए, तकनीकी रूप से, आप नियमों मोड़ कर सकते हैं ...

संपादित करें: अभी इस बारे में सोच, तो आप शायद HttpContext.Items नीचे ViewBag साथ कि आप तकनीकी रूप से अभी भी उपयोग कर रहे थे बदल सकते तो स्टोरेज के लिए व्यूबैग, लेकिन इसे एक रैपर जोड़ने के लिए जो इसे सुरक्षित रूप से सुरक्षित रूप से टाइप की गई महसूस करता है।

उदा।

namespace Your.Namespace 
{ 
    public class MessageCollection : IMessageCollection 
    { 
     public IList<string> Errors { get; protected set; } 
     protected MessageCollection() 
     { 
      //Initialization stuff here 
      Errors = new List<string>(); 
     } 

     private const string HttpContextKey = "__MessageCollection"; 
     public static MessageCollection Current 
     { 
      get 
      { 
       var httpContext = HttpContext.Current; 
       if (httpContext == null) throw new InvalidOperationException("MessageCollection must be used in the context of a web application."); 

       if (httpContext.Items[HttpContextKey] == null) 
       { 
        httpContext.Items[HttpContextKey] = new MessageCollection(); 
       } 

       return httpContext.Items[HttpContextKey] as MessageCollection; 
      } 
     } 
    } 
} 

तो बस इस तरह अपने नियंत्रक में इसे पाने:

[HttpGet] 
public ActionResult Index() 
{ 
    MessageCollection.Current.AddError("Uh oh!"); 

    return View(); 
} 

या आप एक शॉर्टकट गेटर के साथ एक BaseController हो सकता था ... जैसे आप कुछ इस तरह हो सकता था

protected MessageCollection Messages { get { return MessageCollection.Current; } } 

फिर अपने नियंत्रक में से विरासत में से यह

[HttpGet] 
public ActionResult Index() 
{ 
    Messages.AddError("Uh oh!"); 

    return View(); 
} 

अपने ध्यान में रखते हुए इसे पाने के लिए, सरल अपने web.config बदल (आप कुछ स्थानों में यह करने के लिए आवश्यकता हो सकती है (यानी आपका मुख्य web.config, विचार निर्देशिका web.config और क्षेत्र विचारों निर्देशिका web.config)

<system.web.webPages.razor> 
    <!-- blah --> 
    <pages pageBaseType="System.Web.Mvc.WebViewPage"> 
    <namespaces> 
     <!-- blah --> 
     <add namespace="Your.Namespace" /> 
    </namespaces> 
    </pages> 
</system.web.webPages.razor> 
फिर अपने विचारों में

तुम क्या करने में सक्षम होना चाहिए:

<div class="messages"> 
    @foreach (var error in MessageCollection.Current.Errors) 
    { 
     <span>@error</span> 
    } 
</div> 
+0

यह अनिवार्य रूप से मैं "वर्कअराउंड" के रूप में भी आया था लेकिन मैं इसे नए और रचनात्मक विचारों को जल्दी से बंद करने के डर से सवाल के हिस्से के रूप में नहीं रखना चाहता था। मैं आप और क्रिस दोनों के समान पृष्ठ पर हूं लेकिन मैं उम्मीद कर रहा था कि शायद एमवीसी आर्किटेक्चर में कुछ ऐसा था जो विस्तार के लिए एक विस्तार बिंदु की अनुमति देता था जिसके बारे में मुझे पता नहीं था। – Scott

0

ASP.NET MVC में, आप अपने निपटान ViewBag, ViewData पर है, और TempData (अधिक जानकारी के लिए, this blog post देखें)। ViewBagViewData शब्दकोश के आसपास एक गतिशील रैपर है। यदि आप ViewBag.Prop = "value" करते हैं तो यह ViewData["Prop"] = "value" के बराबर है। जब आप किसी दृश्य में Model संपत्ति का उपयोग करते हैं, तो आप ViewData.Model पुनर्प्राप्त कर रहे हैं। अपने आप के लिए देखो:

public abstract class WebViewPage<TModel> : WebViewPage 
{ 
    private ViewDataDictionary<TModel> _viewData; 
    public new AjaxHelper<TModel> Ajax { get; set; } 
    public new HtmlHelper<TModel> Html { get; set; } 
    public new TModel Model { get { return ViewData.Model; } } 
} 

हम या तो ViewBag या ViewData का उपयोग कर अपने विशेष गुण धारण करने के लिए करके अपना अंतिम लक्ष्य को हासिल कर सकते हैं।

public abstract class CustomWebViewPage<TModel> : WebViewPage<TModel> 
{ 
    public IList<string> Messages 
    { 
     get { return ViewBag.Messages ?? (ViewBag.Messages = new List<string>()); } 
    } 
} 

अब आप अपने दृश्य पर जाकर निम्नलिखित के साथ लाइन @model YourModelClass (पहली पंक्ति) की जगह:

@inherits CustomWebViewPage<YourModelClass> 

पहला कदम संपत्ति आप चाहते हैं के साथ WebViewPage<TModel> के एक कस्टम व्युत्पत्ति बनाने के लिए है अब आप अपने विचार में Messages संपत्ति का उपयोग कर सकते हैं।

@String.Join(", ", Messages) 

अपने नियंत्रकों में उपयोग करने के लिए, आप शायद Controller से भी निकाले जाते हैं और वहाँ प्रॉपर्टी जोड़ना चाहते हैं जाएगा।

public abstract class CustomControllerBase : Controller 
{ 
    public IList<string> Messages 
    { 
     get 
     { 
      return ViewBag.Messages ?? (ViewBag.Messages = new List<string>()); 
     } 
    } 
} 

अब यदि आप उस नियंत्रक से प्राप्त करते हैं, तो आप अपनी नई संपत्ति का उपयोग कर सकते हैं। जो कुछ भी आप सूची में डालते हैं वह भी आपके लिए उपलब्ध होगा।

public class ExampleController : CustomControllerBase 
{ 
    public ActionResult Index() 
    { 
     Messages.Add("This is a message"); 
     return View(); 
    } 
} 

मैंने व्यूबैग का उपयोग किया क्योंकि इससे संपत्ति गेटटर कम हो गई। यदि आप चाहें तो ViewData के साथ आप वही काम कर सकते हैं (ViewData["Messages"])।

यह उतना ही नहीं है जितना Model लागू किया गया है क्योंकि कोई व्यक्ति आपकी संपत्ति को गलती से ओवरराइट कर सकता है अगर वे आपके द्वारा सहेजी जा रही कुंजी का उपयोग करने के लिए होते हैं, लेकिन यह पर्याप्त रूप से समकक्ष होने के लिए पर्याप्त है यदि आप अभी सुनिश्चित करते हैं एक अनूठी कुंजी का प्रयोग करें।

यदि आप गहरी खुदाई करते हैं, तो आप ViewDataDictionary से प्राप्त कर सकते हैं और अपनी संपत्ति वहां रख सकते हैं, फिर कुछ नियंत्रक को ओवरराइड करें और इसके बजाय इसका उपयोग करने के तरीकों को देखें। तब आपकी संपत्ति बिल्कुल Model जैसी ही होगी। लेकिन मैं इसे तुम्हारे पास छोड़ दूंगा - मुझे नहीं लगता कि यह इसके लायक है।

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