लेआउट के लिए डेटा पास करें जो सभी पृष्ठों के लिए सामान्य हैं


124

मेरे पास एक वेबसाइट है जिसमें एक लेआउट पृष्ठ है। हालाँकि इस लेआउट पेज में डेटा है जो सभी पेज मॉडल को ऐसे पेज का शीर्षक, पेज का नाम और वह स्थान प्रदान करना चाहिए जहां हम वास्तव में एक HTML सहायक के लिए हैं जो मैंने किया था जो कुछ कार्रवाई करता है। इसके अलावा प्रत्येक पृष्ठ के अपने दृश्य मॉडल गुण हैं।

मैं यह कैसे कर सकता हूँ? ऐसा लगता है कि इसका एक बुरा विचार एक लेआउट टाइप करने के लिए है लेकिन मैं थ्रेसेस इन्फोस कैसे गुजरता हूं?


10
यहाँ उत्तरों को पढ़ने वाले किसी भी व्यक्ति के लिए, कृपया stackoverflow.com/a/21130867/706346 देखें जहाँ आपको एक बहुत ही सरल और निरर्थक समाधान दिखाई देगा, जो यहाँ पर कुछ भी पोस्ट किया गया है।
एवरहोम यिसरेल

5
@AvrohomYisroel अच्छा सुझाव। हालांकि मैं @ कोलिन बेकन के दृष्टिकोण को पसंद करता हूं क्योंकि यह मजबूत टाइप्ड है और इसमें नहीं है ViewBag। शायद वरीयताओं की बात है। हालांकि आपकी टिप्पणी को खारिज कर दिया
जेपी हेल्लेमन्स ने

mvc 5 के लिए यह उत्तर देखें: stackoverflow.com/a/46783375/5519026
लाज़ ज़िया

जवाबों:


143

यदि आपको प्रत्येक पृष्ठ पर समान गुण पास करना आवश्यक है, तो एक बेस व्यूमॉडल बनाना जो आपके सभी व्यू मॉडल द्वारा उपयोग किया जाता है, बुद्धिमान होगा। आपका लेआउट पृष्ठ फिर इस आधार मॉडल को ले सकता है।

यदि इस डेटा के पीछे तर्क की आवश्यकता है, तो इसे एक आधार नियंत्रक में रखा जाना चाहिए जो आपके सभी नियंत्रकों द्वारा उपयोग किया जाता है।

बहुत सी चीजें हैं जो आप कर सकते हैं, महत्वपूर्ण दृष्टिकोण एक ही कोड को कई स्थानों पर दोहराना नहीं है।

संपादित करें: नीचे दी गई टिप्पणियों से अपडेट करें

यहाँ अवधारणा को प्रदर्शित करने के लिए एक सरल उदाहरण है।

एक बेस व्यू मॉडल बनाएं जो सभी व्यू मॉडल से विरासत में मिलेगा।

public abstract class ViewModelBase
{
    public string Name { get; set; }
}

public class HomeViewModel : ViewModelBase
{
}

आपका लेआउट पृष्ठ इसे मॉडल के रूप में ले सकता है।

@model ViewModelBase
<!DOCTYPE html>
<html>
    <head>
        <meta name="viewport" content="width=device-width" />
        <title>Test</title>
    </head>
    <body>
        <header>
            Hello @Model.Name
        </header>
        <div>
            @this.RenderBody()
        </div>
    </body>
</html>

अंत में डेटा को एक्शन विधि में सेट करें।

public class HomeController
{
    public ActionResult Index()
    {
        return this.View(new HomeViewModel { Name = "Bacon" });
    }
}

12
लेकिन डेटा लेआउट में उपयोग किया जाता है। मैं लेआउट में डेटा कैसे पास कर सकता हूं?
रशिनो

2
उत्तम! मैंने अपनी त्रुटि देखी। मैं देखने के लिए मॉडल पारित करना भूल गया .. क्या एक लंगड़ा त्रुटि। धन्यवाद!
रशिनो

7
इस दृष्टिकोण के साथ समस्या यह है कि कभी-कभी प्रत्येक दृश्य में एक ViewModel नहीं होता है, इसलिए यह उस स्थिति में काम नहीं करेगा: O /
Cacho Santa

16
लेकिन क्या इसके लिए जरूरी नहीं है कि हर कंट्रोलर और हर एक्शन में {Name = "बेकन"} कोड शामिल हो? और अगर मैं ViewModelBase में एक और संपत्ति जोड़ना चाहता हूं, तो मुझे प्रत्येक नियंत्रक और प्रत्येक कार्रवाई पर जाना होगा और उस संपत्ति को आबाद करने के लिए कोड जोड़ना होगा? आपने उल्लेख किया है "अगर तर्क की आवश्यकता है [...] इसे एक आधार नियंत्रक में डाल दिया जाना चाहिए [...]"। हर नियंत्रक और हर क्रिया में इस दोहराया कोड को खत्म करने के लिए यह कैसे काम करेगा?
ली

5
@Lee यदि यह सभी पृष्ठों पर सामान्य डेटा है, तो एक आधार नियंत्रक वह जगह है जहाँ आप इसे डालेंगे। आपके नियंत्रक तब इस आधार नियंत्रक से इनहेरिट करते हैं। उदा public class HomeController : BaseController। इस तरह से सामान्य कोड को केवल एक बार लिखा जाना चाहिए और इसे सभी नियंत्रकों पर लागू किया जा सकता है।
कॉलिन बेकन

73

मैंने लेआउट में रेजर के लिए RenderAction html हेल्पर का इस्तेमाल किया।

@{
   Html.RenderAction("Action", "Controller");
 }

मुझे इसके लिए सरल स्ट्रिंग की आवश्यकता थी। तो मेरी कार्रवाई स्ट्रिंग लौटाती है और इसे देखने में आसान लिखती है। लेकिन अगर आपको जटिल डेटा की आवश्यकता है तो आप PartialViewResult और मॉडल वापस कर सकते हैं।

 public PartialViewResult Action()
    {
        var model = someList;
        return PartialView("~/Views/Shared/_maPartialView.cshtml", model);
    }

आपको बस अपने द्वारा बनाए गए आंशिक दृश्य '_maPartialView.cshtml' के मॉडल की शुरुआत की आवश्यकता है

@model List<WhatEverYourObjeIs>

तब आप HTML के साथ उस आंशिक दृश्य में मॉडल में डेटा का उपयोग कर सकते हैं।


18
यह दूर और सबसे अच्छा जवाब है!
जिंजरब्रेडबॉय

@gingerbreadboy ने सहमति व्यक्त की कि यह अच्छे एनकैप्सुलेशन और चिंताओं को अलग करने को बढ़ावा देता है।
ए-डब

35

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


1
यह वास्तव में कम से कम दर्दनाक समाधान की तरह लगता है, क्या कोई डाउनसाइड हैं? +1
प्रारूप

2
निश्चित रूप से सबसे अच्छा समाधान और मुझे कोई डाउनसाइड नहीं दिखता है।
विकिटोर ज़िकला

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

3
यह जो मुझे देता है वह लेआउट के लिए एक मॉडल जोड़ने की क्षमता है, जो सभी मॉडलों को सभी नियंत्रकों के सभी तरीकों में एकल "सुपर" मॉडल से प्राप्त करने के लिए पुनर्गठन के बिना, एक परियोजना में जो पहले से मौजूद है। यदि आप स्क्रैच से शुरू कर रहे हैं, तो आप अपने सभी मॉडलों को आम रूट से प्राप्त करना चुन सकते हैं।
डेनक्युम

5
@ColinBacon इस विकल्प का एक और लाभ यह है कि आपके कार्यों को हमेशा देखने के मॉडल की आवश्यकता नहीं है। इसके अलावा, मेरा तर्क है कि डेवलपर्स को यह जानने की ज़रूरत है कि उन्हें हमेशा अपने विचार मॉडल को आधार से विरासत में प्राप्त करना चाहिए एक नुकसान है।
जोश नू

28

संभवतः, इसके लिए प्राथमिक उपयोग का मामला सभी (या बहुसंख्यक) नियंत्रक क्रियाओं के लिए बेस मॉडल प्राप्त करना है।

यह देखते हुए कि, मैंने इनमें से कई उत्तरों के संयोजन का उपयोग किया है, कॉलिन बेकन के उत्तर पर प्राथमिक सूअर का बच्चा।

यह सही है कि यह अभी भी नियंत्रक तर्क है क्योंकि हम किसी दृश्य पर वापस लौटने के लिए एक दृश्यदर्शी को आबाद कर रहे हैं। इस प्रकार इसे लगाने का सही स्थान नियंत्रक में है।

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

हम अभी भी दृढ़ता से टाइप किए गए ViewModel के अतिरिक्त लाभ चाहते हैं

इस प्रकार, मैंने एक BaseViewModel और BaseController बनाया है। सभी ViewModels नियंत्रक क्रमशः BaseViewModel और BaseController से वारिस होंगे।

कोड:

BaseController

public class BaseController : Controller
{
    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);

        var model = filterContext.Controller.ViewData.Model as BaseViewModel;

        model.AwesomeModelProperty = "Awesome Property Value";
        model.FooterModel = this.getFooterModel();
    }

    protected FooterModel getFooterModel()
    {
        FooterModel model = new FooterModel();
        model.FooterModelProperty = "OMG Becky!!! Another Awesome Property!";
    }
}

इस SO पोस्ट से लिए गए OnActionExecuted के उपयोग पर ध्यान दें

HomeController

public class HomeController : BaseController
{
    public ActionResult Index(string id)
    {
        HomeIndexModel model = new HomeIndexModel();

        // populate HomeIndexModel ...

        return View(model);
    }
}

BaseViewModel

public class BaseViewModel
{
    public string AwesomeModelProperty { get; set; }
    public FooterModel FooterModel { get; set; }
}

HomeViewModel

public class HomeIndexModel : BaseViewModel
{

    public string FirstName { get; set; }

    // other awesome properties
}

FooterModel

public class FooterModel
{
    public string FooterModelProperty { get; set; }
}

Layout.cshtml

@model WebSite.Models.BaseViewModel
<!DOCTYPE html>
<html>
<head>
    < ... meta tags and styles and whatnot ... >
</head>
<body>
    <header>
        @{ Html.RenderPartial("_Nav", Model.FooterModel.FooterModelProperty);}
    </header>

    <main>
        <div class="container">
            @RenderBody()
        </div>

        @{ Html.RenderPartial("_AnotherPartial", Model); }
        @{ Html.RenderPartial("_Contact"); }
    </main>

    <footer>
        @{ Html.RenderPartial("_Footer", Model.FooterModel); }
    </footer>

    < ... render scripts ... >

    @RenderSection("scripts", required: false)
</body>
</html>

_Nav.cshtml

@model string
<nav>
    <ul>
        <li>
            <a href="@Model" target="_blank">Mind Blown!</a>
        </li>
    </ul>
</nav>

उम्मीद है कि यह मदद करता है।


2
मैंने इस दृष्टिकोण का उपयोग किया, लेकिन आधार वर्ग के बजाय इंटरफ़ेस से विरासत में प्राप्त करना पसंद करते हैं। तो मैंने किया: var मॉडल = filterContext.Controller.ViewData.Model IBaseViewModel के रूप में अगर (मॉडल! = Null) {model.AwesomeModelProperty = "बहुत बढ़िया संपत्ति मूल्य"; }
टॉम जेरकेन

2
महान जवाब, मैंने इसे अन्य सभी को पसंद किया।
ज्योन

1
शानदार जवाब, लेकिन मेरा एक सवाल है। "क्या होगा अगर मेरे पास कुछ विचार हैं जो ViewModels नहीं है ...?"
इस्मा हारो

यह कोशिश की, लेकिन सूचकांक कार्रवाई पर, OnActionExecuted FooterModel को भरता है और फिर एक नया HomeIndexModel एक शून्य FooterModel के साथ बनाया जाता है :(
स्टीवकेव

1
@drizzie: आपके आधार नियंत्रक में, मॉडल फ़िल्टर विधि में एक स्थानीय चर है: var मॉडल = filterContext.Controller.ViewData.Model BaseViewModel के रूप में। मुझे समझ नहीं आता कि एमवीसी कैसे समझती है कि यह स्थानीय वैरिएबल मॉडल के समान है जिसे होमकंट्रोलर देखने के लिए भेज रहा है।
होमन बहरीन

9

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

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

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

अपडेट करें

आप एक पेज एक्सटेंशन भी बना सकते हैं जो आपको उपयोग करने की अनुमति देगा this

//Allows typed "this.Controller()." in cshtml files
public static class MyPageExtensions {
    public static _BaseController Controller(this WebViewPage page) => Controller<_BaseController>(page);
    public static T Controller<T>(this WebViewPage page) where T : _BaseController => (T)page.ViewContext.Controller;
}

तब आपको केवल this.Controller()नियंत्रक का उपयोग करने के लिए याद रखना होगा ।

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

या विशिष्ट नियंत्रक जो इनहेरिट करता है _BaseController...

@{
    var myController = this.Controller<MyControllerType>();
}

इस .net कोर में इसके बराबर क्या है? जैसा कि ViewContext.Controller मौजूद नहीं है और विरासत श्रृंखला में कुछ बदलाव है
जयंत त्यागराजन

4

यदि आप एक पूरे मॉडल को पास करना चाहते हैं तो लेआउट में जाएं:

@model ViewAsModelBase
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta charset="utf-8"/>
    <link href="/img/phytech_icon.ico" rel="shortcut icon" type="image/x-icon" />
    <title>@ViewBag.Title</title>
    @RenderSection("styles", required: false)    
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
    @RenderSection("scripts", required: false)
    @RenderSection("head", required: false)
</head>
<body>
    @Html.Action("_Header","Controller", new {model = Model})
    <section id="content">
        @RenderBody()
    </section>      
    @RenderSection("footer", required: false)
</body>
</html>

और इस नियंत्रक में जोड़ें:

public ActionResult _Header(ViewAsModelBase model)

4

मुझे नहीं लगता कि इनमें से कोई भी उत्तर बड़े उद्यम स्तर के आवेदन के लिए पर्याप्त लचीला है। मैं ViewBag के अति प्रयोग का प्रशंसक नहीं हूं, लेकिन इस मामले में, लचीलेपन के लिए, मैं एक अपवाद बनाऊंगा। यहाँ मैं क्या करूँगा ...

आपके सभी नियंत्रकों पर एक आधार नियंत्रक होना चाहिए। अपने आधार नियंत्रक में अपना लेआउट डेटा जोड़ें OnActionExecuting (या यदि आप इसे स्थगित करना चाहते हैं तो OnActionExecuted) ...

public class BaseController : Controller
{
    protected override void OnActionExecuting(ActionExecutingContext     
        filterContext)
    {
        ViewBag.LayoutViewModel = MyLayoutViewModel;
    }
}

public class HomeController : BaseController
{
    public ActionResult Index()
    {
        return View(homeModel);
    }
}

फिर अपने _Loutout.cshtml में ViewBag से अपना ViewModel खींचें ...

@{
  LayoutViewModel model = (LayoutViewModel)ViewBag.LayoutViewModel;
}

<h1>@model.Title</h1>

या ...

<h1>@ViewBag.LayoutViewModel.Title</h1>

ऐसा करना आपके पृष्ठ के नियंत्रकों या दृश्य मॉडल के लिए कोडिंग में हस्तक्षेप नहीं करता है।


मुझे आपका विचार पसंद है लेकिन अगर आपके पास एक MyLayoutViewModelगतिशील रूप से निर्मित है, तो मैं OnActionExecutingविधि के कुछ मापदंडों को कैसे पारित कर सकता हूं ?
राजमंड बर्गज

1
उह, आपको अभी भी base.OnActionExecuting(filterContext)अपनी OnActionExecutingविधि की आवश्यकता है !!!
एरिक

4

बेस दृश्य बनाना जो लेआउट दृश्य मॉडल का प्रतिनिधित्व करता है एक भयानक दृष्टिकोण है। कल्पना करें कि आप एक मॉडल रखना चाहते हैं जो लेआउट में परिभाषित नेविगेशन का प्रतिनिधित्व करता है। करोगे क्या CustomersViewModel : LayoutNavigationViewModel? क्यों? आपको हर एक दृश्य मॉडल के माध्यम से नेविगेशन मॉडल डेटा क्यों पास करना चाहिए जो आपके पास समाधान में है?

लेआउट दृश्य मॉडल को अपने दम पर समर्पित किया जाना चाहिए, बाकी दर्शकों को उस पर निर्भर रहने के लिए मजबूर नहीं करना चाहिए।

इसके बजाय, आप इसे अपनी _Layout.cshtmlफ़ाइल में कर सकते हैं :

@{ var model = DependencyResolver.Current.GetService<MyNamespace.LayoutViewModel>(); }

सबसे महत्वपूर्ण बात, हमें इसकी आवश्यकता नहीं है new LayoutViewModel()और हम उन सभी निर्भरताओं को प्राप्त करेंगे जो LayoutViewModelहमारे लिए हल हो गई हैं।

जैसे

public class LayoutViewModel
{
    private readonly DataContext dataContext;
    private readonly ApplicationUserManager userManager;

    public LayoutViewModel(DataContext dataContext, ApplicationUserManager userManager)
    {
    }
}

आप इस मॉडल को कहां से भरेंगे? एक बेसकंट्रोलर में भी?
ndberg

मुझे लगता है कि यह Scopedएएसपी..नेट कोर में एक लेआउट मॉडल ऑब्जेक्ट के लिए एक अच्छा विचार होगा ।
जेम्स विल्किंस

मेरे पास देखने के लिए एक निर्भरता नहीं है। यह निश्चित रूप से "एमवीसी" नहीं है। सेवा लोकेटर एक विरोधी पैटर्न है
जिम्मन

आम धारणा के विपरीत, सेवा लोकेटर एक विरोधी पैटर्न नहीं है और वास्तव में इसका एमवीसी से कोई लेना-देना नहीं है, क्या आप सिर्फ बज़ शब्द @ जीवमान में फेंक रहे हैं? blog.gauffin.org/2012/09/service-locator-is-not-an-ant-pattern
hyankov

उस लेख में Jgauffin का मुख्य बिंदु यह प्रतीत होता है कि शब्द "एंटी-पैटर्न" को सेवा लोकेटर पर लागू नहीं किया जाना चाहिए, क्योंकि SL के कम से कम कुछ मान्य उपयोग हो सकते हैं। एक उचित बिंदु। हालाँकि, जैसा कि उनकी कुछ चर्चा टिप्पणियों में स्पष्ट है, वे सुझाव देते हैं कि पुस्तकालयों और रूपरेखाओं का निर्माण करते समय SL एक वैध दृष्टिकोण हो सकता है, यह आवश्यक नहीं है कि आवेदन बनाते समय (जो मैं ओपी के प्रश्न पर विचार करूं और यह चर्चा यहां हो। चारों ओर घूमना)।
जिम्मन

3

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

public class SubLocationsViewModel
{
    public string city { get; set; }
    public string state { get; set; }
}

और आप गतिशील रूप से शहर और राज्य प्राप्त करना चाहते हैं। उदाहरण के लिए

अपने index.cshtml में आप ViewBag में इन दो चर को रख सकते हैं

@model  MyProject.Models.ViewModel.SubLocationsViewModel
@{
    ViewBag.City = Model.city;
    ViewBag.State = Model.state;
}

और फिर अपने layout.cshtml में आप उन व्यूबैग चर का उपयोग कर सकते हैं

<div class="text-wrap">
    <div class="heading">@ViewBag.City @ViewBag.State</div>
</div>

यह बहुत अच्छा काम करता है, @stun_Gravy भूमिका या उपयोगकर्ता पहुंच स्तर जैसे डेटा पास करने के लिए ViewBag का उपयोग करने में गिरावट है?
3not3

3

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

@inject IService myService

फिर बाद में लेआउट दृश्य में:

@if (await myService.GetBoolValue()) {
   // Good to go...
}

फिर से, वास्तुकला के संदर्भ में साफ नहीं है (जाहिर है कि सेवा को सीधे दृश्य में इंजेक्ट नहीं किया जाना चाहिए), लेकिन यह काम पूरा करता है।


सबसे साफ तरीका नहीं? मैं असहमत हूं। मुझे लगता है कि यह उतना ही साफ है जितना कि यह हो जाता है: ऑब्जेक्ट उस स्थान से पारित किया जाता है जहां इसे सीधे उस स्थान पर बनाया जाता है जहां आप इसे होना चाहते हैं, आइटम के साथ "प्रदूषणकारी" अन्य नियंत्रकों के बिना उन्हें देखने की आवश्यकता नहीं है। का उपयोग करना @injectसबसे अच्छा उपाय है, मेरी राय में।
dasblinkenlight

1
इस बारे में अधिक सोचना शायद आप सही कह रहे हैं। तथ्य यह है कि यह विधि बहुत दर्द से बचाती है एक संकेत है कि शायद यह सबसे साफ तरीका है। मैं एक बहुत बड़े ASP.NET कोर ऐप पर काम कर रहा हूं और मैं इस पैटर्न का उपयोग नेविगेशन ब्रेडक्रंब लॉजिक, हेडर डेटा जो कि अधिकांश पृष्ठों पर है, जैसी चीजों के लिए कर रहा हूं। मैंने इस तरह से ऐसा करने से बहुत दर्द से बचा है।
एंड्रयू

2

आप RenderSection का उपयोग भी कर सकते हैं , यह आपको अपने Modelडेटा को _Layoutदृश्य में इंजेक्ट करने में मदद करता है ।

आप इंजेक्षन कर सकते हैं View Modelडाटा, Json, Script, CSS, HTMLआदि

इस उदाहरण में मैं Jsonअपने Indexव्यू से Layoutव्यू तक इंजेक्ट कर रहा हूं ।

Index.chtml

@section commonLayoutData{

    <script>

        var products = @Html.Raw(Json.Encode(Model.ToList()));

    </script>

    }

_Layout.cshtml

@RenderSection("commonLayoutData", false)

यह एक अलग बेस बनाने की आवश्यकता को समाप्त करता है View Model

आशा किसी की मदद करती है।


1
सही समाधान जब आपको केवल कुछ दृश्यों के लिए कुछ विशिष्ट प्रस्तुत करना होगा।
कुणाल

1

मैंने जो किया वह बहुत सरल है और यह काम करता है

किसी भी नियंत्रक में स्थैतिक संपत्ति की घोषणा करें या आप स्थैतिक मूल्यों के साथ एक डेटा-क्लास बना सकते हैं यदि आप इस तरह चाहते हैं:

public static username = "Admin";
public static UserType = "Administrator";

ये मान संचालन के आधार पर नियंत्रकों द्वारा अद्यतन किए जा सकते हैं। बाद में आप उन्हें अपने _Layout में उपयोग कर सकते हैं

_Layout.cshtml में

@project_name.Controllers.HomeController.username
@project_name.Controllers.HomeController.UserType

1
यह आपके उत्तर के लिए कुछ स्पष्टीकरण जोड़ने में सहायक होता है, इसे और अधिक स्पष्ट और समझने योग्य बनाने के लिए। कृपया stackoverflow.com/help/how-to-answer पढ़ें ।
32cupo

0

किसी ने ViewData पर एक्सटेंशन विधियों का सुझाव क्यों नहीं दिया है?

विकल्प 1

अब तक मुझे लगता है कि समस्या का सबसे कम घुसपैठ और सरल समाधान है। कोई हार्डकोड स्ट्रिंग्स नहीं। कोई प्रतिबंध नहीं लगाया। कोई जादू कोडिंग नहीं। कोई जटिल कोड नहीं।

public static class ViewDataExtensions
{
    private const string TitleData = "Title";
    public static void SetTitle<T>(this ViewDataDictionary<T> viewData, string value) => viewData[TitleData] = value;
    public static string GetTitle<T>(this ViewDataDictionary<T> viewData) => (string)viewData[TitleData] ?? "";
}

पृष्ठ में डेटा सेट करें

ViewData.SetTitle("abc");

विकल्प 2

एक अन्य विकल्प, क्षेत्र की घोषणा को आसान बनाना।

public static class ViewDataExtensions
{
    public static ViewDataField<string, V> Title<V>(this ViewDataDictionary<V> viewData) => new ViewDataField<string, V>(viewData, "Title", "");
}

public class ViewDataField<T,V>
{
    private readonly ViewDataDictionary<V> _viewData;
    private readonly string _field;
    private readonly T _defaultValue;

    public ViewDataField(ViewDataDictionary<V> viewData, string field, T defaultValue)
    {
        _viewData = viewData;
        _field = field;
        _defaultValue = defaultValue;
    }

    public T Value {
        get => (T)(_viewData[_field] ?? _defaultValue);
        set => _viewData[_field] = value;
    }
}

पृष्ठ में डेटा सेट करें। घोषणा पहले विकल्प की तुलना में आसान है, लेकिन उपयोग वाक्यविन्यास थोड़ा लंबा है।

ViewData.Title().Value = "abc";

विकल्प # 3

फिर सभी डिफ़ॉल्ट संबंधित मानों के साथ सभी लेआउट-संबंधित फ़ील्ड वाली एकल ऑब्जेक्ट को वापस करने के साथ संयोजन कर सकते हैं।

public static class ViewDataExtensions
{
    private const string LayoutField = "Layout";
    public static LayoutData Layout<T>(this ViewDataDictionary<T> viewData) => 
        (LayoutData)(viewData[LayoutField] ?? (viewData[LayoutField] = new LayoutData()));
}

public class LayoutData
{
    public string Title { get; set; } = "";
}

पृष्ठ में डेटा सेट करें

var layout = ViewData.Layout();
layout.Title = "abc";

इस तीसरे विकल्प के कई लाभ हैं और मुझे लगता है कि ज्यादातर मामलों में सबसे अच्छा विकल्प है:

  • खेतों और डिफ़ॉल्ट मूल्यों की सरलतम घोषणा।

  • कई फ़ील्ड सेट करते समय सबसे सरल उपयोग वाक्यविन्यास।

  • ViewData (जैसे लेआउट, हेडर, नेविगेशन) में विभिन्न प्रकार के डेटा सेट करने की अनुमति देता है।

  • लेआउट कोड वर्ग के भीतर अतिरिक्त कोड और तर्क की अनुमति देता है।

PS _ViewImports.cshtml में ViewDataExtensions का नाम जोड़ना न भूलें


0

आप App_Code फ़ोल्डर में एक रेजर फ़ाइल बना सकते हैं और फिर इसे अपने दृश्य पृष्ठों से एक्सेस कर सकते हैं।

परियोजना> भंडार / IdentityRepository.cs

namespace Infrastructure.Repository
{
    public class IdentityRepository : IIdentityRepository
    {
        private readonly ISystemSettings _systemSettings;
        private readonly ISessionDataManager _sessionDataManager;

        public IdentityRepository(
            ISystemSettings systemSettings
            )
        {
            _systemSettings = systemSettings;
        }

        public string GetCurrentUserName()
        {
            return HttpContext.Current.User.Identity.Name;
        }
    }
}

परियोजना> App_Code / IdentityRepositoryViewFunctions.cshtml:

@using System.Web.Mvc
@using Infrastructure.Repository
@functions
{
    public static IIdentityRepository IdentityRepositoryInstance
    {
        get { return DependencyResolver.Current.GetService<IIdentityRepository>(); }
    }

    public static string GetCurrentUserName
    {
        get
        {
            var identityRepo = IdentityRepositoryInstance;
            if (identityRepo != null)
            {
                return identityRepo.GetCurrentUserName();
            }
            return null;
        }
    }
}

प्रोजेक्ट> व्यू / शेयर / _Layout.cshtml (या कोई अन्य .cshtml फ़ाइल)

<div>
    @IdentityRepositoryViewFunctions.GetCurrentUserName
</div>

-1

इसके माध्यम से जाने के बजाय आप हमेशा एक और दृष्टिकोण का उपयोग कर सकते हैं जो तेज भी है

साझा निर्देशिका में एक नया आंशिक दृश्य बनाएं और अपने लेआउट में अपने आंशिक दृश्य को कॉल करें

@Html.Partial("MyPartialView")

अपने आंशिक दृश्य में आप अपने db को कॉल कर सकते हैं और प्रदर्शन कर सकते हैं कि आप क्या करना चाहते हैं

@{
    IEnumerable<HOXAT.Models.CourseCategory> categories = new HOXAT.Models.HOXATEntities().CourseCategories;
}

<div>
//do what ever here
</div>

यह मानते हुए कि आपने अपना एंटिटी फ्रेमवर्क डेटाबेस जोड़ा है


1
डाउनकास्टिंग करना क्योंकि यह कभी भी अपने स्वयं के मॉडल को प्राप्त करने के लिए दृश्य की जिम्मेदारी नहीं होनी चाहिए।
ऑक्सोन्हैमर

-1

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


@ कोडस्मिथ क्या? मैं एक समाधान प्रदान कर रहा हूं।
मका

मेरा बुरा, सोचा कि यह एक सवाल था, लेकिन देखिए यह अब एक प्रतिक्रिया है, हटा दी गई।
कोडस्मिथ

यदि यह प्रश्न का उत्तर देने का प्रयास है, तो इसे स्पष्ट किया जाना चाहिए। कमेंट्री को सहन किया जाता है लेकिन इसे पूरे उत्तर पर हावी नहीं होना चाहिए; इसके अलावा, Google के लिए युक्तियां मान्य उत्तर नहीं देती हैं।
त्रिवेणी

-6

आप इस तरह का उपयोग कर सकते हैं:

 @{ 
    ApplicationDbContext db = new ApplicationDbContext();
    IEnumerable<YourModel> bd_recent = db.YourModel.Where(m => m.Pin == true).OrderByDescending(m=>m.ID).Select(m => m);
}
<div class="col-md-12">
    <div class="panel panel-default">
        <div class="panel-body">
            <div class="baner1">
                <h3 class="bb-hred">Recent Posts</h3>
                @foreach(var item in bd_recent)
                {
                    <a href="/BaiDangs/BaiDangChiTiet/@item.ID">@item.Name</a>
                }
            </div>
        </div>
    </div>
</div>

7
दृश्य में डेटाबेस के साथ जुड़ना वास्तव में बुरा विचार है।
1_बग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.