146

I have a website which have a layout page. However this layout page have data which all pages model must provide such page title, page name and the location where we actually are for an HTML helper I did which perform some action. Also each page have their own view models properties.

How can I do this? It seems that its a bad idea to type a layout but how do I pass theses infos?

Curtis
  • 101,612
  • 66
  • 270
  • 352
Rushino
  • 9,415
  • 16
  • 53
  • 93
  • 12
    For anyone reading the replies here, please see http://stackoverflow.com/a/21130867/706346 where you'll see a much simpler and neater solution that anything posted here. – Avrohom Yisroel Jun 21 '15 at 13:52
  • 5
    @AvrohomYisroel good suggestion. However I prefer the approach of @Colin Bacon because it is strong typed and not in the `ViewBag`. Perhaps a matter of preferences. Upvoted your comment though – JP Hellemons May 03 '16 at 10:53
  • for mvc 5 see this answer: https://stackoverflow.com/a/46783375/5519026 – LazZiya Oct 17 '17 at 06:03

19 Answers19

157

If you are required to pass the same properties to each page, then creating a base viewmodel that is used by all your view models would be wise. Your layout page can then take this base model.

If there is logic required behind this data, then this should be put into a base controller that is used by all your controllers.

There are a lot of things you could do, the important approach being not to repeat the same code in multiple places.

Edit: Update from comments below

Here is a simple example to demonstrate the concept.

Create a base view model that all view models will inherit from.

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

public class HomeViewModel : ViewModelBase
{
}

Your layout page can take this as it's model.

@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>

Finally set the data in the action method.

public class HomeController
{
    public ActionResult Index()
    {
        return this.View(new HomeViewModel { Name = "Bacon" });
    }
}
Colin Bacon
  • 15,436
  • 7
  • 52
  • 72
  • 13
    But the data is used in the layout. How can i pass the data to the layout ? – Rushino Nov 05 '12 at 15:29
  • Yeah i though about this. However i am pretty sure ive tried this and it didn't work. I will retry to see what went wrong and come back to you. – Rushino Nov 05 '12 at 19:21
  • 2
    Perfect! I saw my error. I forgot to pass the model to the view.. what a lame error. Thanks! – Rushino Nov 05 '12 at 23:35
  • 7
    the problem with this approach is that sometimes not every view has a ViewModel, so this won't work in that case :O/ – Cacho Santa Jul 02 '14 at 13:14
  • 22
    But wouldn't this require that every controller and every action include the { Name = "Bacon" } code? And if I wanted to add another property to ViewModelBase, I'd have to go to every controller and every action and add the code to populate that property? You mentioned "If there is logic required [...] this should be put into a base controller [...]". How would this work to eliminate this repeated code in every controller and every action? – Lee Jul 11 '14 at 16:14
  • 6
    @Lee If it is common data across all pages, a base controller is where you would put this. Your controllers then inherit from this base controller. e.g. `public class HomeController : BaseController`. This way the common code only needs to be written once and can be applied to all controllers. – Colin Bacon Jul 11 '14 at 16:24
  • 1
    This works perfect if my RenderBody() not rendering any view without model. If i have a view is already has a model then this layout view throwing error saying "The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[MVC_Application.Models.Country]', but this dictionary requires a model item of type 'MVC_Application.Models.ViewModelBase'." – rafidheen Nov 28 '14 at 11:11
  • @cacho: I have modified a bit to make this solution work with every view model by checking model is not null first: if (Model != null) {
    Hello @Model.Message
    }
    – Minh Nguyen Mar 02 '16 at 14:34
  • Two questions. 1) What if I have some views that does not have a ViewModel? 2) What are you using an "abstract" class for the ViewModelBase instead of a normal class? – Isma Haro Apr 12 '17 at 18:08
  • @HristoYankov unless you provide a resource for a better approach, your comment is disregarded! – Subliminal Hash May 21 '17 at 21:37
  • @HristoYankov fair enough! apologies! – Subliminal Hash May 26 '17 at 15:07
81

I used RenderAction html helper for razor in layout.

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

I needed it for simple string. So my action returns string and writes it down easy in view. But if you need complex data you can return PartialViewResult and model.

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

You just need to put your model begining of the partial view '_maPartialView.cshtml' that you created

@model List<WhatEverYourObjeIs>

Then you can use data in the model in that partial view with html.

Burk
  • 2,969
  • 1
  • 23
  • 24
37

Another option is to create a separate LayoutModel class with all the properties you will need in the layout, and then stuff an instance of this class into ViewBag. I use Controller.OnActionExecuting method to populate it. Then, at the start of layout you can pull this object back from ViewBag and continue to access this strongly typed object.

DenNukem
  • 8,014
  • 3
  • 40
  • 45
  • 1
    This actually sounds like least painful solution, are there any downsides? +1 – formatc Apr 20 '15 at 17:42
  • 2
    Definitely the best solution and I don't see any downsides. – Wiktor Zychla May 20 '15 at 12:51
  • 1
    I honestly think this i a way better solution, the accepted version goes bananas when you're working with colections – Bobby Tables Jun 27 '15 at 21:25
  • 7
    I don't see what this is giving you. If you've got a class with all the properties you need for the layout, why bother adding it to the ViewBag only to have to cast it back again? Use the model in the layout view, you can still populate the model in `OnActionExecuting`. Using ViewBag also means you loose type safety in your controller, never a good thing. – Colin Bacon Aug 19 '15 at 08:14
  • I agree with Colin but +1 for an interesting workaround. – Liviu Mandras Sep 23 '15 at 12:00
  • 4
    What this gives me is the ability to add a model for layout, without having to restructure all models to inherit from the single "super" model in all methods of all controllers, in a project that already exists. If you're starting from scratch, you may chose to derive all your models from the common root instead. – DenNukem Sep 23 '15 at 23:08
  • 5
    @ColinBacon another advantage to this option is that your Actions don't need to always have view models. Also, I'd argue that developers needing to know that they must always inherit their view models from a base is a disadvantage. – Josh Noe Nov 05 '15 at 00:13
  • Absolutely the best solution. Another great advantage of this answer is when you want to work with viewmodels of the layout and the pages separately. It can't be done by using the accepted answer's solution. – Arad Alvand Jun 07 '18 at 16:08
  • @AmirHosseinAhmadi Exactly this. If you have a BlogController with actions for Index and Blog inheritance will lock you into having the same layout for both. Which is great exactly until your client says, "Hey I want the layout with the big logos and extra text on the index pages but the small one on the detail pages, why is that so difficult?" – WhiteleyJ Jan 15 '19 at 17:17
  • @DenNukem Changing controllers from : Controller to : BaseController would take a couple of minutes even if you had 100 controllers. Seems like a small issue. – niico Mar 06 '19 at 13:22
  • @WhiteleyJ This isn't an issue, you can put all required layout data in the BaseModel in a BaseController, just like you can put it in the ViewBag. You can also do this Controller if that makes sense. I don't see the issue. – niico Mar 06 '19 at 13:25
36

Presumably, the primary use case for this is to get a base model to the view for all (or the majority of) controller actions.

Given that, I've used a combination of several of these answers, primary piggy backing on Colin Bacon's answer.

It is correct that this is still controller logic because we are populating a viewmodel to return to a view. Thus the correct place to put this is in the controller.

We want this to happen on all controllers because we use this for the layout page. I am using it for partial views that are rendered in the layout page.

We also still want the added benefit of a strongly typed ViewModel

Thus, I have created a BaseViewModel and BaseController. All ViewModels Controllers will inherit from BaseViewModel and BaseController respectively.

The code:

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!";
    }
}

Note the use of OnActionExecuted as taken from this SO post

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>

Hopefully this helps.

Community
  • 1
  • 1
drizzie
  • 3,351
  • 2
  • 27
  • 32
  • 2
    I used this approach, but prefer inheriting from an interface rather than a base class. So I did: var model = filterContext.Controller.ViewData.Model as IBaseViewModel if (model != null) { model.AwesomeModelProperty = "Awesome Property Value"; } – Tom Gerken Oct 19 '16 at 21:05
  • 2
    great answer, I preferred this one to all the others. – Jynn Apr 12 '17 at 11:09
  • 1
    Great answer, but I have a question. "What if I have some views that doesn't have ViewModels... ?" – Isma Haro Apr 12 '17 at 18:36
  • 1
    Tried this but on the Index Action, OnActionExecuted fills the FooterModel and then a new HomeIndexModel is created with a null FooterModel :( – SteveCav Jun 15 '17 at 23:36
  • 1
    @drizzie: in your base controller, model is a local variable in the Filter method: var model = filterContext.Controller.ViewData.Model as BaseViewModel. I do not understand how MVC understand that this local variable is the same as the model that HomeController is sending to view. – Hooman Bahreini Sep 14 '17 at 06:31
11

There's another way to handle this if the project is using .Net Core or .Net. Maybe not the cleanest way from an architectural point of view, but it avoids a lot of pain involved with the other answers. Simply inject a service in the Razor layout and then call a method that gets the necessary data:

@inject IService myService

Then later in the layout view:

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

Again, not clean in terms of architecture (obviously the service shouldn't be injected directly in the view), but it gets the job done.

Thomas927
  • 853
  • 1
  • 11
  • 19
Andrew
  • 1,581
  • 3
  • 18
  • 31
  • 1
    Not the cleanest way? I disagree. I think this is as clean as it gets: the object is passed from the place where it is created straight to the place where you want it to be, without "polluting" other controllers with items they don't need to see. Using `@inject` is the best solution, in my opinion. – Sergey Kalinichenko Feb 29 '20 at 11:16
  • 3
    Thinking about this more maybe you're right. The fact that this method avoids so much pain is a sign that perhaps it is the cleanest way. I have been working on a very large ASP.NET Core app and I'm using this pattern for things like navigation breadcrumb logic, header data that is on most pages, things like that. I have avoided so much pain by doing it this way instead. – Andrew Mar 01 '20 at 06:37
  • This technique is also used by _LoginPartial.cshtml which is an auto generated view when you scaffolding an Asp.Net Core Razor Page project with Identity enabled. – Bochen Lin Jan 29 '22 at 04:30
9

You don't have to mess with actions or change the model, just use a base controller and cast the existing controller from the layout viewcontext.

Create a base controller with the desired common data (title/page/location etc) and action initialization...

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

    protected override void OnActionExecuting(ActionExecutingContext filterContext) {

        MyCommonValue = 12345;

        base.OnActionExecuting(filterContext);
    }
}

Make sure every controller uses the base controller...

public class UserController:_BaseController {...

Cast the existing base controller from the view context in your _Layout.cshml page...

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

Now you can refer to values in your base controller from your layout page.

@myController.MyCommonValue

UPDATE

You could also create a page extension that would allow you to use 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;
}

Then you only have to remember to use this.Controller() when you want the controller.

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

or specific controller that inherits from _BaseController...

@{
    var myController = this.Controller<MyControllerType>();
}
Carter Medlin
  • 11,857
  • 5
  • 62
  • 68
5

if you want to pass an entire model go like so in the layout:

@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>

and add this in the controller:

public ActionResult _Header(ViewAsModelBase model)
Yakir Manor
  • 4,687
  • 1
  • 32
  • 25
5

I do not think any of these answers are flexible enough for a large enterprise level application. I'm not a fan of overusing the ViewBag, but in this case, for flexibility, I'd make an exception. Here's what I'd do...

You should have a base controller on all of your controllers. Add your Layout data OnActionExecuting in your base controller (or OnActionExecuted if you want to defer that)...

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

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

Then in your _Layout.cshtml pull your ViewModel from the ViewBag...

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

<h1>@model.Title</h1>

Or...

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

Doing this doesn't interfere with the coding for your page's controllers or view models.

  • I like your idea but what about if you have a `MyLayoutViewModel` dynamically created, how can i pass some parameters to `OnActionExecuting` method ? – Rey Apr 01 '17 at 09:08
  • 1
    Uh, you still need `base.OnActionExecuting(filterContext)` in your `OnActionExecuting` method!!! – ErikE Apr 25 '17 at 01:42
4

Creating a base view which represents the Layout view model is a terrible approach. Imagine that you want to have a model which represents the navigation defined in the layout. Would you do CustomersViewModel : LayoutNavigationViewModel? Why? Why should you pass the navigation model data through every single view model that you have in the solution?

The Layout view model should be dedicated, on its own and should not force the rest of the view models to depend on it.

Instead, you can do this, in your _Layout.cshtml file:

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

Most importantly, we don't need to new LayoutViewModel() and we will get all the dependencies that LayoutViewModel has, resolved for us.

e.g.

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

    public LayoutViewModel(DataContext dataContext, ApplicationUserManager userManager)
    {
    }
}
hyankov
  • 4,049
  • 1
  • 29
  • 46
  • Where do you fill this model? In a BaseController as well? – ndberg Nov 21 '17 at 14:13
  • I imagine this would be a good idea for a `Scoped` layout model object in ASP..Net Core as well. – James Wilkins Feb 04 '18 at 05:34
  • I wouldn't have the view go fetch a dependency. That is definitely not "MVC". [Service Locator is an anti-pattern](http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/). – Jiveman Sep 12 '18 at 22:53
  • Contrary to popular belief, Service Locator is not an anti-pattern and actually this has nothing to do with MVC, are you just throwing in buzz words @Jiveman? http://blog.gauffin.org/2012/09/service-locator-is-not-an-anti-pattern/ – hyankov Nov 21 '18 at 20:02
  • Jgauffin's main point in that article seems to be that the term "anti-pattern" shouldn't be applied to Service Locator, since there can be at least some valid uses of SL. A fair point. However, as is evident in some of his own discussion comments, he suggests that while SL might be a valid approach when building libraries and frameworks, it is not necessarily recommended when building applications (which I would consider OP's question and this discussion here to be revolving around). – Jiveman Nov 22 '18 at 08:19
3

Other answers have covered pretty much everything about how we can pass model to our layout page. But I have found a way using which you can pass variables to your layout page dynamically without using any model or partial view in your layout. Let us say you have this model -

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

And you want to get city and state dynamically. For e.g

in your index.cshtml you can put these two variables in ViewBag

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

And then in your layout.cshtml you can access those viewbag variables

<div class="text-wrap">
    <div class="heading">@ViewBag.City @ViewBag.State</div>
</div>
Chirag K
  • 2,394
  • 2
  • 16
  • 23
  • this works great, @stun_Gravy is there a downfall using ViewBag to pass data like role or user access level? – 3not3 Aug 30 '17 at 22:18
3

You can also make use of RenderSection , it helps to you to inject your Model data into the _Layout view.

You can inject View Model Data, Json, Script , CSS, HTML etc

In this example I am injecting Json from my Index View to Layout View.

Index.chtml

@section commonLayoutData{

    <script>

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

    </script>

    }

_Layout.cshtml

@RenderSection("commonLayoutData", false)

This eliminates the need of creating a separate Base View Model.

Hope helps someone.

Shaiju T
  • 6,201
  • 20
  • 104
  • 196
1

Why hasn't anyone suggested extension methods on ViewData?

Option #1

Seems to me by far the least intrusive and simplest solution to the problem. No hardcoded strings. No imposed restrictions. No magic coding. No complex code.

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] ?? "";
}

Set data in the page

ViewData.SetTitle("abc");

Option #2

Another option, making the field declaration easier.

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;
    }
}

Set data in the page. Declaration is easier than first option, but usage syntax is slightly longer.

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

Option #3

Then can combine that with returning a single object containing all layout-related fields with their default values.

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; } = "";
}

Set data in the page

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

This third option has several benefits and I think is the best option in most cases:

  • Simplest declaration of fields and default values.

  • Simplest usage syntax when setting multiple fields.

  • Allows setting various kinds of data in the ViewData (eg. Layout, Header, Navigation).

  • Allows additional code and logic within LayoutData class.

P.S. Don't forget to add the namespace of ViewDataExtensions in _ViewImports.cshtml

Etienne Charland
  • 3,424
  • 5
  • 28
  • 58
1

The best way to use static strings such as page title, page name and the location etc, is to define via ViewData. Just define required ViewData in ViewStart.cshtml

@{
    Layout = "_Layout";
    ViewData["Title"] = "Title";
    ViewData["Address"] = "1425 Lane, Skardu,<br> Pakistan";
}

and call whenever require like

<div class="rn-info-content">
     <h2 class="rn-contact-title">Address</h2>
         <address>
             @Html.Raw(ViewData["Address"].ToString())
         </address>
</div>
0

You could create a razor file in the App_Code folder and then access it from your view pages.

Project>Repository/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;
        }
    }
}

Project>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;
        }
    }
}

Project>Views/Shared/_Layout.cshtml (or any other .cshtml file)

<div>
    @IdentityRepositoryViewFunctions.GetCurrentUserName
</div>
Joel Wiklund
  • 1,697
  • 2
  • 18
  • 24
0

In .NET Core, you can use View Components to do this.

https://learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-5.0

From the link above, add a class Inheriting from ViewComponent

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ViewComponentSample.Models;

namespace ViewComponentSample.ViewComponents
{
    public class PriorityListViewComponent : ViewComponent
    {
        private readonly ToDoContext db;

        public PriorityListViewComponent(ToDoContext context)
        {
            db = context;
        }

        public async Task<IViewComponentResult> InvokeAsync(
        int maxPriority, bool isDone)
        {
            var items = await GetItemsAsync(maxPriority, isDone);
            return View(items);
        }
        private Task<List<TodoItem>> GetItemsAsync(int maxPriority, bool isDone)
        {
            return db.ToDo.Where(x => x.IsDone == isDone &&
                                 x.Priority <= maxPriority).ToListAsync();
        }
    }
}

Then in your view (_layout in my case)

@await Component.InvokeAsync("PriorityList", new { maxPriority = 4, isDone = true })

If you need a view, make a folder at ~/Views/Shared/Components/<Component Name>/Default.cshtml. You need to make the folder Components then in that, make a folder with your component name. In the example above, PriorityList.

Adam C
  • 86
  • 1
  • 4
-1

instead of going through this you can always use another approach which is also fast

create a new partial view in the Shared Directory and call your partial view in your layout as

@Html.Partial("MyPartialView")

in your partial view you can call your db and perform what ever you want to do

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

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

assuming you have added your Entity Framework Database

Asad Ali
  • 111
  • 2
  • 7
-1

what i did is very simple and it's works

Declare Static property in any controller or you can make a data-class with static values if you want like this:

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

These values can be updated by the controllers based on operations. later you can use them in your _Layout

In _layout.cshtml

@project_name.Controllers.HomeController.username
@project_name.Controllers.HomeController.UserType
Sayed Muhammad Idrees
  • 1,245
  • 15
  • 25
  • 1
    It is always helpful add some explanation to your answer, to make it more clear and understandable. Please read https://stackoverflow.com/help/how-to-answer. – 32cupo Jun 02 '20 at 09:35
  • 1
    This "answer" is wrong - static variables are shared between all the user sessions, therefore all the users will get the same values. This is definitely not what is required. Further more, it adds security risk as well. – Kaspars Ozols Oct 15 '20 at 12:35
-2

It's incredible that nobody has said this over here. Passing a viewmodel through a base controller is a mess. We are using user claims to pass info to the layout page (for showing user data on the navbar for example). There is one more advantage. The data is stored via cookies, so there is no need to retrieve the data in each request via partials. Just do some googling "asp net identity claims".

makore
  • 47
  • 3
  • @CodeSmith what? I'm providing a solution. – makore Jun 28 '18 at 17:14
  • My bad, thought this was a question but see it's a response now, deleted. – CodeSmith Jun 28 '18 at 17:21
  • If this is an attempt at answering the question, it should be clarified. Commentary is tolerated but it should not be dominating the entire answer; also, tips for what to google do not constitute a valid answer. – tripleee Dec 13 '18 at 13:27
-9

You can use like this:

 @{ 
    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>