नियंत्रकों के लिए आधार वर्ग का उपयोग किए बिना सभी दृश्यों के लिए ViewBag गुण कैसे सेट करें?


96

अतीत में, मैंने आम गुणों को अटका दिया है, जैसे कि वर्तमान उपयोगकर्ता, एक सामान्य आधार नियंत्रक से विरासत में मिलने वाले सभी नियंत्रकों द्वारा ViewData / ViewBag पर एक वैश्विक फैशन में।

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

मुझे आश्चर्य है कि क्या MVC पाइपलाइन में इस तरह का कोड डालने का कोई वैकल्पिक तरीका है?

जवाबों:


22

मेरे द्वारा अन-ट्राई किया गया, लेकिन आप अपने विचारों को पंजीकृत करने और फिर सक्रियण प्रक्रिया के दौरान दृश्य डेटा सेट करने पर विचार कर सकते हैं ।

क्योंकि दृश्य ऑन-द-फ़्लाई में पंजीकृत हैं, पंजीकरण सिंटैक्स आपको Activatedईवेंट से कनेक्ट करने में मदद नहीं करता है , इसलिए आपको इसे इसके लिए सेट करना होगा Module:

class SetViewBagItemsModule : Module
{
    protected override void AttachToComponentRegistration(
        IComponentRegistration registration,
        IComponentRegistry registry)
    {
        if (typeof(WebViewPage).IsAssignableFrom(registration.Activator.LimitType))
        {
            registration.Activated += (s, e) => {
                ((WebViewPage)e.Instance).ViewBag.Global = "global";
            };
        }
    }
}

यह उन लोगों में से एक हो सकता है "केवल उपकरण का एक हथौड़ा" -प्रकार सुझाव मुझसे; इस पर प्राप्त करने के लिए सरल MVC- सक्षम तरीके हो सकते हैं।

संपादित करें: वैकल्पिक, कम कोड दृष्टिकोण - बस नियंत्रक से संलग्न करें

public class SetViewBagItemsModule: Module
{
    protected override void AttachToComponentRegistration(IComponentRegistry cr,
                                                      IComponentRegistration reg)
    {
        Type limitType = reg.Activator.LimitType;
        if (typeof(Controller).IsAssignableFrom(limitType))
        {
            registration.Activated += (s, e) =>
            {
                dynamic viewBag = ((Controller)e.Instance).ViewBag;
                viewBag.Config = e.Context.Resolve<Config>();
                viewBag.Identity = e.Context.Resolve<IIdentity>();
            };
        }
    }
}

संपादित करें 2: एक और दृष्टिकोण जो नियंत्रक पंजीकरण कोड से सीधे काम करता है:

builder.RegisterControllers(asm)
    .OnActivated(e => {
        dynamic viewBag = ((Controller)e.Instance).ViewBag;
        viewBag.Config = e.Context.Resolve<Config>();
        viewBag.Identity = e.Context.Resolve<IIdentity>();
    });

वास्तव में मुझे जो चाहिए था। बॉक्स से बाहर काम करने का उत्तर अपडेट किया गया
स्कॉट विंस्टीन

महान सामान - आपके दृष्टिकोण के आधार पर मैंने एक और सरलीकरण जोड़ा है, इस बार बिना मॉड्यूल की आवश्यकता के।
निकोलस ब्लमहार्ट

का Resolveहिस्सा क्या है e.Context.Resolve? मुझे उल्लेख करना चाहिए कि मुझे
निमेज

243

सबसे अच्छा तरीका ActionFilterAttribute का उपयोग करना है और अपने वैश्विक में अपने कस्टम वर्ग को पंजीकृत करना है। असैक्स (Application_Start)

public class UserProfilePictureActionFilter : ActionFilterAttribute
{

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        filterContext.Controller.ViewBag.IsAuthenticated = MembershipService.IsAuthenticated;
        filterContext.Controller.ViewBag.IsAdmin = MembershipService.IsAdmin;

        var userProfile = MembershipService.GetCurrentUserProfile();
        if (userProfile != null)
        {
            filterContext.Controller.ViewBag.Avatar = userProfile.Picture;
        }
    }

}

अपने कस्टम वर्ग को अपने वैश्विक में पंजीकृत करें। असैक्स (Application_Start)

protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        GlobalFilters.Filters.Add(new UserProfilePictureActionFilter(), 0);

    }

फिर आप इसे सभी दृश्यों में उपयोग कर सकते हैं

@ViewBag.IsAdmin
@ViewBag.IsAuthenticated
@ViewBag.Avatar

इसके अलावा एक और तरीका है

HtmlHelper पर एक विस्तार विधि बनाना

[Extension()]
public string MyTest(System.Web.Mvc.HtmlHelper htmlHelper)
{
    return "This is a test";
}

फिर आप इसे सभी दृश्यों में उपयोग कर सकते हैं

@Html.MyTest()

9
मुझे समझ में नहीं आता है कि यह अधिक क्यों नहीं उत्कीर्ण किया गया है; यह दूसरों की तुलना में बहुत कम आक्रामक दृष्टिकोण है
joshcomley

5
इसे खोजने के लिए 8 घंटे का शोध ... एकदम सही जवाब। बहुत बहुत धन्यवाद।
डेल्ट्री

3
+1 वैश्विक डेटा को एकीकृत करने का अच्छा और स्वच्छ तरीका। मैंने इस तकनीक का उपयोग सभी पृष्ठों पर अपने साइट संस्करण को पंजीकृत करने के लिए किया है।
विल बर्कफोर्ड

4
शानदार, आसान और विनीत समाधान।
यूजेन टिम्म

3
लेकिन आईओसी कहां है? यानी आप बाहर कैसे स्विच करेंगे MembershipService?
ड्रूज

39

चूंकि ViewBag गुण हैं, परिभाषा के अनुसार, व्यू प्रेजेंटेशन और किसी भी लाइट व्यू लॉजिक से बंधा हुआ है जो कि आवश्यक हो सकता है, मैं एक बेस WebViewPage बनाऊंगा और प्रॉपर्टीज को पेज इनिशियलाइज़ेशन पर सेट करूँगा । यह बार-बार तर्क और सामान्य कार्यक्षमता के लिए एक आधार नियंत्रक की अवधारणा के समान है, लेकिन आपके विचारों के लिए:

    public abstract class ApplicationViewPage<T> : WebViewPage<T>
    {
        protected override void InitializePage()
        {
            SetViewBagDefaultProperties();
            base.InitializePage();
        }

        private void SetViewBagDefaultProperties()
        {
            ViewBag.GlobalProperty = "MyValue";
        }
    }

और फिर \Views\Web.config, pageBaseTypeसंपत्ति सेट करें :

<system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="MyNamespace.ApplicationViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>

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

@Proro निश्चित रूप से सच है, लेकिन फिर मैं तर्क दूंगा कि ViewBag का मतलब राज्य में एक निरंतर स्रोत होना नहीं है। लगता है कि आप सत्र स्थिति में उस डेटा को चाहेंगे और फिर आप अपने बेस व्यू पेज में इसे बाहर निकाल सकते हैं और मौजूद होने पर ViewBag में सेट कर सकते हैं।
ब्रैंडन लिंटन

आपके पास एक मान्य बिंदु है, लेकिन बहुत ज्यादा हर कोई अन्य दृश्यों में एक दृश्य में डेटा सेट का उपयोग करता है; जैसे जब आप पृष्ठ के शीर्षक को एक दृश्य में सेट करते हैं और आपका साझा लेआउट दृश्य तब HTML शीर्षक के <शीर्षक> टैग में इसे प्रिंट करता है। मैं इसे "मास्टर" लेआउट दृश्य बनाने के लिए "बच्चे" के दृश्य में "व्यूबाग.डैटेबल्सजैस" जैसे बूलियन सेट करके इसे एक कदम आगे ले जाना पसंद करता हूं, इसमें एचटीएम के सिर पर उचित जेएस संदर्भ शामिल हैं। जब तक यह लेआउट संबंधित है, मुझे लगता है कि ऐसा करना ठीक है।
पेद्रो

शीर्षक टैग की स्थिति में @Pedro अच्छी तरह से, आमतौर पर एक ViewBag.Titleसंपत्ति सेट करने वाले प्रत्येक दृश्य के साथ संभाला जाता है और फिर साझा लेआउट में केवल एक चीज होती है <title>@ViewBag.Title</title>। यह वास्तव में किसी आधार अनुप्रयोग दृश्य पृष्ठ की तरह कुछ के लिए उपयुक्त नहीं होगा क्योंकि प्रत्येक दृश्य अलग है, और आधार दृश्य पृष्ठ उन डेटा के लिए होगा जो वास्तव में सभी विचारों के लिए सामान्य है।
ब्रैंडन लिंटन

@Proro मैं समझता हूं कि आप क्या कह रहे हैं और मुझे लगता है कि ब्रैंडन वहां से चूक गए। मैं एक कस्टम WebViewPage का उपयोग कर रहा था और मैंने कस्टम WebViewPage में एक कस्टम प्रॉपर्टी का उपयोग करके किसी एक दृश्य से कुछ डेटा को लेआउट दृश्य में भेजने का प्रयास किया। जब मैं संपत्ति को दृश्य में सेट करता हूं, तो यह मेरे कस्टम WebViewPage में ViewData को अद्यतन करेगा लेकिन जब यह लेआउट दृश्य को मिला, तो ViewData प्रविष्टि पहले ही खो गई थी। मैंने कस्टम वेब व्यूपेज में ViewContext.Controller.ViewData ["SomeValue"] का उपयोग करके इसे प्राप्त किया। मुझे उम्मीद है कि यह किसी की मदद करता है।
इमरान राशिद

17

पैसे पर ब्रैंडन का पद सही है। तथ्य की बात के रूप में, मैं इसे एक कदम आगे ले जाऊंगा और कहूंगा कि आपको बस अपनी सामान्य वस्तुओं को आधार वेबवेपेज के गुणों के रूप में जोड़ना चाहिए ताकि आपको हर एक दृश्य में व्यूबाग से आइटम न डालना पड़े। मैं अपना CurrentUser सेटअप इस तरह से करता हूं।


मैं इस त्रुटि के साथ काम करने के लिए नहीं मिल सका'ASP._Page_Views_Shared__Layout_cshtml' does not contain a definition for 'MyProp' and no extension method 'MyProp' accepting a first argument of type 'ASP._Page_Views_Shared__Layout_cshtml' could be found (are you missing a using directive or an assembly reference?)
स्प्रिंटस्टार

इस पर +1, यह वही है जो मैं एक गैर-स्थैतिक उपयोगिता वर्ग का एक उदाहरण साझा करने के लिए कर रहा हूं, जिसे विश्व स्तर पर सभी दृश्यों में उपलब्ध होने की आवश्यकता है।
निक कॉड

9

आप एक कस्टम ActionResult का उपयोग कर सकते हैं:

public class  GlobalView : ActionResult 
{
    public override void ExecuteResult(ControllerContext context)
    {
        context.Controller.ViewData["Global"] = "global";
    }
}

या यहां तक ​​कि एक ActionFilter:

public class  GlobalView : ActionFilterAttribute 
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        filterContext.Result = new ViewResult() {ViewData = new ViewDataDictionary()};

        base.OnActionExecuting(filterContext);
    }
}

MVC 2 परियोजना खुली थी, लेकिन दोनों तकनीक अभी भी मामूली बदलाव के साथ लागू होती हैं।


5

आपको क्रियाओं के साथ गड़बड़ करने या मॉडल को बदलने की ज़रूरत नहीं है, बस एक आधार नियंत्रक का उपयोग करें और लेआउट दृश्यदर्शी से मौजूदा नियंत्रक कास्ट करें।

वांछित सामान्य डेटा (शीर्षक / पृष्ठ / स्थान आदि) और कार्रवाई आरंभ के साथ एक आधार नियंत्रक बनाएं ...

public abstract class _BaseController:Controller {
    public Int32 MyCommonValue { get; private set; }

    protected override void OnActionExecuting(ActionExecutingContext filterContext) {

        MyCommonValue = 12345;

        base.OnActionExecuting(filterContext);
    }
}

सुनिश्चित करें कि हर नियंत्रक आधार नियंत्रक का उपयोग करता है ...

public class UserController:_BaseController {...

अपने _Layout.cshmlपृष्ठ में दृश्य संदर्भ से मौजूदा आधार नियंत्रक कास्ट करें ...

@{
    var myController = (_BaseController)ViewContext.Controller;
}

अब आप अपने लेआउट पेज से अपने आधार नियंत्रक के मूल्यों का उल्लेख कर सकते हैं।

@myController.MyCommonValue

3

यदि आप अपने विचारों में संपत्तियों के लिए संकलन समय और इंटेलीसेंस चाहते हैं तो ViewBag जाने का रास्ता नहीं है।

BaseViewModel वर्ग पर विचार करें और आपके अन्य दृश्य मॉडल इस वर्ग से प्राप्त हुए हैं, जैसे:

बेस ViewModel

public class BaseViewModel
{
    public bool IsAdmin { get; set; }

    public BaseViewModel(IUserService userService)
    {
        IsAdmin = userService.IsAdmin;
    }
}

विशिष्ट ViewModel देखें

public class WidgetViewModel : BaseViewModel
{
    public string WidgetName { get; set;}
}

अब व्यू कोड सीधे व्यू में प्रॉपर्टी को एक्सेस कर सकता है

<p>Is Admin: @Model.IsAdmin</p>

2

मैंने निम्नलिखित दृष्टिकोण को सबसे कुशल पाया है और _ViewStart.chtml फ़ाइल और सशर्त उपयोग करते हुए उत्कृष्ट नियंत्रण देता है:

_ ViewStart :

@{
 Layout = "~/Views/Shared/_Layout.cshtml";

 var CurrentView = ViewContext.Controller.ValueProvider.GetValue("controller").RawValue.ToString();

 if (CurrentView == "ViewA" || CurrentView == "ViewB" || CurrentView == "ViewC")
    {
      PageData["Profile"] = db.GetUserAccessProfile();
    }
}

दृश्य :

@{
   var UserProfile= PageData["Profile"] as List<string>;
 }

नोट :

पृष्ठडेटा दृश्य में पूरी तरह से काम करेगा; हालाँकि, एक आंशिक दृश्य के मामले में, इसे व्यू से बच्चे के आंशिक में पास करना होगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.