ASP.NET MVC रेज़र पास लेआउट के लिए मॉडल


97

मैं जो देखता हूं वह एक स्ट्रिंग लेआउट संपत्ति है। लेकिन मैं स्पष्ट रूप से लेआउट के लिए एक मॉडल कैसे पारित कर सकता हूं?


मेरे पास अलग-अलग मॉडल के साथ कई पेज हैं, लेकिन एक ही लेआउट
साइबेरियाई

2
स्टैकओवरफ़्लो प्रश्न का उत्तर लगता है कि आप क्या पूछ रहे हैं: stackoverflow.com/questions/13225315/…
पॉल

मुझे यह समस्या नहीं हो रही है। Modelमें उपलब्ध है _Layout। मैं MVC5 का उपयोग कर रहा हूं।
toddmo

जवाबों:


66

लगता है कि अगर आपने इस समस्या को देखा है तो आपने अपने व्यूअमॉडल को थोड़ा गलत बनाया है।

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


11
"व्यक्तिगत रूप से मैं कभी भी लेआउट पृष्ठ नहीं लिखूंगा।" क्यों? मेरा मतलब है, आप सभी पृष्ठों में दिखाई देने वाली साइड डायनामिक सामग्री को कैसे संभालते हैं? क्या आप नियंत्रकों को दृश्य से छोड़ते हैं? / शायद आप लेआउट से RenderAction का उपयोग करने का मतलब है? (मैं अभी इसे देख रहा हूँ)
इगलासियस

52
@eglasius, मेरे द्वारा उपयोग किए जाने वाले समाधान इस बात पर निर्भर करते हैं कि हम किस प्रकार की सामग्री के आधार पर भिन्न हैं। लेकिन एक सामान्य समाधान है कि लेआउट पृष्ठ में अपने स्वयं के डेटा की आवश्यकता वाले भागों को रेंडर करने के लिए रेंडरएक्शन का उपयोग किया जाए। लेआउट पेज टाइप करना मुझे पसंद नहीं है इसका कारण यह है कि यह आपको हमेशा सभी दृश्य मॉडल में "आधार" दृश्यम विरासत में प्राप्त करने के लिए मजबूर करेगा। मेरे अनुभव में यह आमतौर पर एक बहुत अच्छा विचार नहीं है और बहुत समय है जब आपके पास मुद्दे होंगे जब डिजाइन को बदलने के लिए देर हो जाएगी (या इसे लंबा समय लगेगा)।
मटियास जैकबसन

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

4
मेरे पास 2 समाधान हैं: लेआउट के लिए एक सामान्य मॉडल इसलिए मैं MyLayoutModel <MyViewModel> दृश्य मॉडल के लिए, केवल लेआउट में MyViewModel के साथ RenderPartial का उपयोग कर सकता हूं। या गतिशील कैश्ड भागों के लिए रेंडरएशन का उपयोग करके पृष्ठ के कुछ हिस्सों को आंशिक रूप से प्रस्तुत करें और गतिशील भागों के लिए अजाक्स कॉल करें। लेकिन मैं पहले समाधान को पसंद करता हूं क्योंकि यह अधिक खोज इंजन के अनुकूल है, और आसानी से अजाक्स अपडेट के साथ जोड़ा जा सकता है।
साफ्टलाइन

4
विरासत कोड पर काम करना जहां वास्तव में ऐसा किया गया है। यह एक दुःस्वप्न है। अपने लेआउट टाइप न करें ... pleeease!

79
  1. अपने नियंत्रक (या आधार नियंत्रक) में एक संपत्ति जोड़ें जिसे MainLayoutViewModel (या जो भी) आप जिस भी प्रकार का उपयोग करना चाहते हैं, के साथ कहते हैं।
  2. अपने कंट्रोलर (या बेस कंट्रोलर) के कंस्ट्रक्टर में, तत्काल टाइप करें और उसे प्रॉपर्टी पर सेट करें।
  3. इसे ViewData फ़ील्ड (या ViewBag) पर सेट करें
  4. लेआउट पृष्ठ में, उस प्रॉपर्टी को अपने प्रकार पर कास्ट करें।

उदाहरण: नियंत्रक:

public class MyController : Controller
{
    public MainLayoutViewModel MainLayoutViewModel { get; set; }

    public MyController()
    {
        this.MainLayoutViewModel = new MainLayoutViewModel();//has property PageTitle
        this.MainLayoutViewModel.PageTitle = "my title";

        this.ViewData["MainLayoutViewModel"] = this.MainLayoutViewModel;
    }

}

उदाहरण पृष्ठ का शीर्ष पृष्ठ

@{
var viewModel = (MainLayoutViewModel)ViewBag.MainLayoutViewModel;
}

अब आप टाइप किए गए ऑब्जेक्ट पर पूर्ण पहुंच के साथ अपने लेआउट पेज में चर 'viewModel' का संदर्भ ले सकते हैं।

मुझे यह दृष्टिकोण पसंद है क्योंकि यह नियंत्रक है जो लेआउट को नियंत्रित करता है, जबकि व्यक्तिगत पेज व्यूमोडल लेआउट अज्ञेयवादी रहता है।

MVC कोर के लिए नोट्स


पहली बार कॉल करने पर Mvc Core ViewData / ViewBag की सामग्री को उड़ा देता है। इसका मतलब यह है कि निर्माण में ViewData असाइन करना काम नहीं करता है। हालांकि, क्या काम करता है, एक का उपयोग IActionFilterकर रहा है और एक ही काम कर रहा है OnActionExecutingMyActionFilterअपने पर रखो MyController

public class MyActionFilter: Attribute, IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext context)
        {
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            var myController= context.Controller as MyController;

            if (myController!= null)
            {
                myController.Layout = new MainLayoutViewModel
                {

                };

                myController.ViewBag.MainLayoutViewModel= myController.Layout;
            }
        }
    }

1
मैं फिर से मिलता हूं ... लेकिन डायनामिक्स / कास्ट रेजर पृष्ठों के लिए बहुत केंद्रीय हैं। एक चीज जो आप कर सकते हैं, वह है मैनललैट व्यूवॉडेल में एक स्टैटिक मेथड जोड़ना, जो आपके लिए कास्टिंग करता है (जैसे MainLayoutViewModel.FromViewBag (this.ViewBag)) ताकि कम से कम कास्ट एक ही जगह पर हो रहा हो और आप वहां अपवादों को बेहतर तरीके से संभाल सकें।
लाठी

@BlackjacketMack अच्छा तरीका है और मैंने इसे ऊपर का उपयोग करके और कुछ संशोधन bcoz बनाकर हासिल किया, जिसकी मुझे एक अलग आवश्यकता थी और इसने वास्तव में मुझे धन्यवाद देने में मदद की। क्या हम TempData का उपयोग करके इसे प्राप्त कर सकते हैं यदि हाँ तो कैसे और नहीं तो plz मुझे बताएं कि इसका उपयोग क्यों नहीं किया जा सकता है। एक बार फिर धन्यवाद।
ज़कर

2
@User - TempData सत्र का उपयोग करता है और हमेशा मुझे थोड़ा सा गुदगुदी लगता है। मेरी समझ यह है कि यह 'रीड-वन' है ताकि जैसे ही आप इसे पढ़ते हैं यह इसे सत्र से हटा देता है (या शायद जैसे ही अनुरोध समाप्त हो जाता है)। यह संभव है कि आप Sql Server (या Dynamo Db) में सत्र को स्टोर करते हैं, इसलिए इस तथ्य पर विचार करें कि आपको MasterLayoutViewModel को क्रमांकित करना होगा ... वह नहीं जो आप सबसे अधिक चाहते हैं। इसलिए मूल रूप से, ViewData में इसे स्थापित करने से यह एक छोटे से लचीले शब्दकोष में मेमोरी में स्टोर हो जाता है, जो बिल को फिट करता है।
लाठी

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

1
हाय करीम एजी, मुझे लगता है कि यह दोनों का एक सा है। मैं ViewData में एक बुरा अभ्यास के रूप में सामान रखने पर विचार करता हूं (यह ट्रैक करना कठिन है, शब्दकोश आधारित है, वास्तव में टाइप नहीं किया गया है) ... लेकिन ... दृढ़ता से टाइप की गई वस्तु में अपने सभी लेआउट गुणों को टाइप करना एक महान अभ्यास है। तो मैं यह कहकर समझौता कर लेता हूं, ठीक है, चलो एक चीज को वहां स्टोर करते हैं, लेकिन क्या बाकी लोग इसे अच्छी तरह से टाइप किए गए ViewModel में बंद कर देते हैं।
ब्लैकजैकमेट

30

यह बहुत ही मूल सामग्री है, बस आपको एक बेस व्यू मॉडल बनाना और सभी को सुनिश्चित करना है! और मैं सभी का मतलब है! आपके विचारों का जो कभी उस लेआउट का उपयोग करेगा, उस आधार मॉडल का उपयोग करने वाले विचार प्राप्त करेगा!

public class SomeViewModel : ViewModelBase
{
    public bool ImNotEmpty = true;
}

public class EmptyViewModel : ViewModelBase
{
}

public abstract class ViewModelBase
{
}

_Layout.cshtml में:

@model Models.ViewModelBase
<!DOCTYPE html>
  <html>
  and so on...

सूचकांक में (उदाहरण के लिए) होम कंट्रोलर में विधि:

    public ActionResult Index()
    {
        var model = new SomeViewModel()
        {
        };
        return View(model);
    }

Index.cshtml:

@model Models.SomeViewModel

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

<div class="row">

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

स्पष्ट रूप से अधिक उन्नत उद्देश्य के लिए आपको इंजेक्शन का उपयोग करके कस्टम स्टैटिक कॉन्टैक्स बनाने पर विचार करना चाहिए और _Layout.chml में उस मॉडल नेमस्पेस को शामिल करना चाहिए।

लेकिन बुनियादी उपयोगकर्ताओं के लिए यह चाल चलेगा


मैं आपसे सहमत हुँ। धन्यवाद।
सेबेस्टियन गुरेरो

1
ऊपर और सिर्फ यह उल्लेख करना चाहते हैं कि यह बेस क्लास के बजाय एक इंटरफेस के साथ भी काम करता है
व्लाद

29

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

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

मेरा समाधान आधार दृश्य मॉडल के साथ भी शुरू होता है:

public class LayoutModel
{
    public LayoutModel(string title)
    {
        Title = title;
    }

    public string Title { get;}
}

तब मैं जो उपयोग करता हूं वह लेआउटमॉडल का एक सामान्य संस्करण है जो इस तरह से लेआउटमॉडल से विरासत में मिला है:

public class LayoutModel<T> : LayoutModel
{
    public LayoutModel(T pageModel, string title) : base(title)
    {
        PageModel = pageModel;
    }

    public T PageModel { get; }
}

इस समाधान के साथ मैंने लेआउट मॉडल और मॉडल के बीच विरासत की आवश्यकता को काट दिया है।

तो अब मैं आगे जा सकते हैं और इस तरह Layout.cshtml में LayoutModel का उपयोग कर सकते हैं:

@model LayoutModel
<!doctype html>
<html>
<head>
<title>@Model.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>

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

@model LayoutModel<Customer>
@{
    var customer = Model.PageModel;
}

<p>Customer name: @customer.Name</p>

अपने नियंत्रक से आप केवल एक प्रकार का लेआउट लौटाते हैं:

public ActionResult Page()
{
    return View(new LayoutModel<Customer>(new Customer() { Name = "Test" }, "Title");
}

1
मल्टीपल इनहेरिटेंस इश्यू और इससे निपटने के तरीके बताने के लिए बोनस! यह स्केलेबिलिटी के लिए बेहतर जवाब है।
ब्रेट स्पेंसर

1
मेरी राय में सबसे अच्छा समाधान। वास्तुकला की दृष्टि से यह स्केलेबल और मेंटेनेंस योग्य है। ऐसा करने का यह सही तरीका है। मुझे ViewBag या ViewData पसंद नहीं था ..... वे दोनों मुझे हैक करने लगते हैं।
जोनाथन अल्फारो

10

आप न केवल आंशिक दृश्य के लिए आवश्यक मॉडल पास करने वाले i के अपने विशिष्ट नियंत्रक के साथ एक नया आंशिक दृश्य जोड़ते हैं और अंत में RenderPartial या RenderAction का उपयोग करके अपने Layout.cshtml पर उल्लिखित आंशिक दृश्य रेंडर करते हैं?

मैं इस विधि का उपयोग उपयोगकर्ता की जानकारी जैसे नाम, प्रोफ़ाइल चित्र और आदि में लॉग दिखाने के लिए करता हूँ।


2
क्या आप कृपया इसे विस्तार से बता सकते हैं? मैं इस तकनीक के माध्यम से जाने वाले कुछ ब्लॉग पोस्ट के लिंक की सराहना करता हूँ
J86

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

3

पुराने प्रश्न लेकिन MVC5 डेवलपर्स के लिए समाधान का उल्लेख करने के लिए, आप Modelसंपत्ति को देखने में उपयोग कर सकते हैं ।

Modelदोनों दृश्य और लेआउट में संपत्ति एक ही साथ assosiated है ViewDataDictionaryताकि आप लेआउट पृष्ठ पर अपने मॉडल पारित करने के लिए किसी भी अतिरिक्त काम करने के लिए नहीं है, वस्तु, और आप की घोषणा करने की जरूरत नहीं है@model MyModelName लेआउट में।

लेकिन ध्यान दें कि जब आप @Model.XXXलेआउट में उपयोग करते हैं तो इंटेलीजेंस संदर्भ मेनू दिखाई नहीं देगा क्योंकि Modelयहां एक गतिशील वस्तु है जैसे कि ViewBag


2

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

public class MyLayoutModel {
    public User CurrentUser {
        get {
            .. get the current user ..
        }
    }
}

फिर दृश्य में

@{
    // Or get if from your DI container
    var myLayoutModel = new MyLayoutModel();
}

, .net कोर में आप इसे छोड़ सकते हैं और निर्भरता इंजेक्शन का उपयोग कर सकते हैं।

@inject My.Namespace.IMyLayoutModel myLayoutModel

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


2

इसे संग्रहीत करने का एक और तरीका है।

  1. बस सभी नियंत्रकों के लिए बेसकंट्रोलर वर्ग को लागू करें

  2. में BaseControllerवर्ग एक विधि है कि उदाहरण के लिए की तरह एक मॉडल वर्ग रिटर्न पैदा करते हैं।

public MenuPageModel GetTopMenu() 
{    

var m = new MenuPageModel();    
// populate your model here    
return m; 

}
  1. और Layoutपेज में आप उस तरीके को कॉल कर सकते हैंGetTopMenu()
@using GJob.Controllers

<header class="header-wrapper border-bottom border-secondary">
  <div class="sticky-header" id="appTopMenu">
    @{
       var menuPageModel = ((BaseController)this.ViewContext.Controller).GetTopMenu();
     }
     @Html.Partial("_TopMainMenu", menuPageModel)
  </div>
</header>

0

मान लें कि आपका मॉडल वस्तुओं का संग्रह है (या शायद एक ही वस्तु)। मॉडल में प्रत्येक वस्तु के लिए निम्न कार्य करें।

1) ViewBag में वह ऑब्जेक्ट डालें जिसे आप दिखाना चाहते हैं। उदाहरण के लिए:

  ViewBag.YourObject = yourObject;

2) _Layout.cshtml के शीर्ष पर एक उपयोग कथन जोड़ें जिसमें आपकी वस्तुओं के लिए वर्ग परिभाषा है। उदाहरण के लिए:

@use YourApplication.YourClasses;

3) जब आप अपने ऑबजेक्ट को संदर्भित करते हैं तो _Layout में इसे डालें। आपने जो (2) में किया उसके कारण आप कास्ट को लागू कर सकते हैं।


-2
public interface IContainsMyModel
{
    ViewModel Model { get; }
}

public class ViewModel : IContainsMyModel
{
    public string MyProperty { set; get; }
    public ViewModel Model { get { return this; } }
}

public class Composition : IContainsMyModel
{
    public ViewModel ViewModel { get; set; }
}

अपने लेआउट में IContainsMyModel का उपयोग करें।

हल किया। इंटरफेस नियम।


1
निश्चित नहीं है कि आप नीचे मतदान क्यों कर रहे थे। एक इंटरफ़ेस का उपयोग करना, जो आपने यहां किया है, उसी के समान मेरे संदर्भ में काम किया है।
कोस्टा

-6

उदाहरण के लिए

@model IList<Model.User>

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

नए @model निर्देश के बारे में अधिक पढ़ें


लेकिन क्या होगा अगर मैं लेआउट मॉडल में संग्रह का पहला तत्व पास करना चाहता हूं?
साइबेरियनग्यू

आपको अपने कंट्रोलर में पहला तत्व लाना है और मॉडल को @model Model.User में सेट करना है
मार्टिन फैबिक

लेकिन मैं चाहता हूं कि मेरा पृष्ठ IList और लेआउट - केवल पहला तत्व
साइबेरियाई

यदि मैंने आपको सही समझा है, तो आप चाहते हैं कि मॉडल IList <SomeThing> हो और देखने में संग्रह का पहला तत्व प्राप्त हो? यदि ऐसा है तो @ Model.First ()
मार्टिन फेबिक

6
पोस्टर पूछ रहा था कि किसी मॉडल को _Layout.cshtml पेज को कैसे पारित किया जाए .. न कि मुख्य दृश्य जो लेआउट का उपयोग करता है।
प्योर.क्रोम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.