What I see is a string Layout property. But how can I pass a model to layout explicitly?
-
I have several page with different model but the same layout – SiberianGuy Nov 11 '10 at 13:35
-
2This stackoverflow question seems to answer what you are asking: http://stackoverflow.com/questions/13225315/pass-data-to-layout-that-are-common-to-all-pages – Paul Jul 27 '14 at 20:39
-
I'm not having this problem. `Model` is available in `_Layout`. I'm using MVC5. – toddmo Aug 28 '16 at 18:48
12 Answers
- Add a property to your controller (or base controller) called MainLayoutViewModel (or whatever) with whatever type you would like to use.
- In the constructor of your controller (or base controller), instantiate the type and set it to the property.
- Set it to the ViewData field (or ViewBag)
- In the Layout page, cast that property to your type.
Example: Controller:
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;
}
}
Example top of Layout Page
@{
var viewModel = (MainLayoutViewModel)ViewBag.MainLayoutViewModel;
}
Now you can reference the variable 'viewModel' in your layout page with full access to the typed object.
I like this approach because it is the controller that controls the layout, while the individual page viewmodels remain layout agnostic.
Notes for MVC Core
Mvc Core appears to blow away the contents of ViewData/ViewBag upon calling each action the first time. What this means is that assigning ViewData in the constructor doesn't work. What does work, however, is using an
IActionFilter
and doing the exact same work in OnActionExecuting
. Put MyActionFilter
on your 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;
}
}
}

- 5,472
- 28
- 32
-
1I get ya...but dynamics/casts are pretty central to razor pages. One thing you could do is add a static method to MainLayoutViewModel which does the casting for you (e.g. MainLayoutViewModel.FromViewBag(this.ViewBag)) so at least the cast is happening in one place and you can better handle exceptions there. – BlackjacketMack Feb 27 '14 at 17:39
-
@BlackjacketMack Good approach and I achieved it using the above and making some modification bcoz I had a diff requirement and this really helped me thanks. Can we achive the same using TempData if yes then how and no then plz tell me why it can't be used. Thanks again. – Zaker Jan 21 '15 at 05:38
-
2@User - TempData uses Session and always feels a little bit kludgy to me. My understanding is that it's 'read-once' so that as soon as you read it it removes it from session (or perhaps as soon as the request is over). It's possible that you store session in Sql Server (or Dynamo Db) so consider the fact that you'd have to serialize the MasterLayoutViewModel...not what you want most likely. So basically, setting it to ViewData stores it in memory in a little flexible dictionary, which fits the bill. – BlackjacketMack Mar 03 '15 at 20:34
-
Simple enough, I used your solution but, I'm new to MVC so, I'm just wondering is this considered a good practice? or at least not a bad one? – Karim AG Oct 28 '15 at 10:36
-
1Hi Karim AG, I think it's a bit of both. I tend to consider storing stuff in ViewData as a bad practice (it's hard to track, dictionary based, not really typed)...BUT...typing out all your layout properties in a strongly typed object is a great practice. So I compromise by saying, ok, let's store one thing in there, but have the rest of it locked down to a good strongly typed ViewModel. – BlackjacketMack Oct 28 '15 at 18:58
-
Do you have any information on MVC Core blowing away ViewData/ViewBag upon calling each action for the first time? Perhaps this has been fixed now? – niico Mar 05 '19 at 23:55
-
At the bottom of my answer above I have a 'Notes for MVC Core' section that should address this. – BlackjacketMack Mar 14 '19 at 18:11
-
@BlackjacketMack I tried your solution but I need to pass an Id from the URL so I can read the correct information from the database to build the viewmodel for the layout. Is it possible? – Patrick Jan 22 '20 at 16:29
-
@Patrick ActionExecutingContext (the 'context' variable) has access to HttpContext so I would suspect you could get the Id from the URL either through the RequestContext (on HttpContext) or possibly via the RouteValues if your routes are setup that way. – BlackjacketMack Jan 22 '20 at 21:15
Seems like you have modeled your viewmodels a bit wrong if you have this problem.
Personally I would never type a layout page. But if you want to do that you should have a base viewmodel that your other viewmodels inherits from and type your layout to the base viewmodel and you pages to the specific once.

- 8,207
- 2
- 34
- 41
-
12"Personally I would never type a layout page." Why? I mean, how do you handle side dynamic content that appears in All pages? Do you skip controllers from the view? / maybe you mean to use RenderAction from the layout? (I'm just looking at it right now) – eglasius Apr 11 '11 at 23:11
-
54@eglasius, The solution I use is different depending on what kind of content we talk about. But a common solution is to use RenderAction to render parts that need their own data in the layout page. The reason I don't like typing the layout page is that it will force you to always inherit a "base" viewmodel in all you specific view models. In my experience this usually isn't a very good idea and a lot of the time you will have issues when it's to late to change the design (or it will take to long). – Mattias Jakobsson Apr 12 '11 at 06:24
-
thx for the answer, already decided for RenderAction a few mins after I posted. What you say in the comment is very right, I just wasn't seeing where to hook at the time. – eglasius Apr 12 '11 at 07:14
-
2What if I want to include the base model by aggregation, not by inheritance? A perfectly legitimate way from the design perspective. How do I handle layout then? – Fyodor Soikin Aug 22 '11 at 15:24
-
-1 because i also think a layout should have a model which can be set in the view or by the action displaying the view. ViewBag is too much magic, and remembers me basic/javascript magic declaration of variables, which leads to hours of debugging. – Softlion Jan 05 '12 at 09:42
-
@Softlion So do you strongly type your layout and have the content views' view models inherit from that type? – Ian Warburton Mar 03 '12 at 15:42
-
4I have 2 solutions: a generic model for the layout so i can use MyLayoutModel
for the view model, using RenderPartial with MyViewModel only in the layout. Or partially render the parts of the page using RenderAction for static cached parts and ajax calls for dynamic parts. But i prefer the first solution as it is more search engines friendly, and be easily combined with ajax updates. – Softlion Mar 05 '12 at 09:19 -
4Working on legacy code where exactly this has been done. It's a nightmare. Don't type your layouts...pleeease! – Sep 19 '13 at 10:47
-
-
1There is only one problem with RenderAction/Action in layout page. Controller instance is made for each such call. This can be even bigger problem if design changes and base controller has to do more work in contructor/before action. That's why my vote goes to @BlackjacketMack, even though i hate using ViewBag (but it's still better than base model). – Stefan Cebulak Aug 09 '14 at 12:50
-
-
@MattiasJakobsson, I have a typed inner-nested layout to provide a common layout for a small subset of pages that share; title, intro, footer type elements. If a page should vary from that, I'd drop the inner layout and include those elements in the view. Do you foresee any issues I may encounter? – Myster May 31 '21 at 21:45
A common solution is to make a base view model which contains the properties used in the layout file and then inherit from the base model to the models used on respective pages.
The problem with this approach is that you now have locked yourself into the problem of a model can only inherit from one other class, and maybe your solution is such that you cannot use inheritance on the model you intended anyways.
My solution also starts of with a base view model:
public class LayoutModel
{
public LayoutModel(string title)
{
Title = title;
}
public string Title { get;}
}
What I then use is a generic version of the LayoutModel which inherits from the LayoutModel, like this:
public class LayoutModel<T> : LayoutModel
{
public LayoutModel(T pageModel, string title) : base(title)
{
PageModel = pageModel;
}
public T PageModel { get; }
}
With this solution I have disconnected the need of having inheritance between the layout model and the model.
So now I can go ahead and use the LayoutModel in Layout.cshtml like this:
@model LayoutModel
<!doctype html>
<html>
<head>
<title>@Model.Title</title>
</head>
<body>
@RenderBody()
</body>
</html>
And on a page you can use the generic LayoutModel like this:
@model LayoutModel<Customer>
@{
var customer = Model.PageModel;
}
<p>Customer name: @customer.Name</p>
From your controller you simply return a model of type LayoutModel:
public ActionResult Page()
{
return View(new LayoutModel<Customer>(new Customer() { Name = "Test" }, "Title");
}

- 2,728
- 27
- 31
-
1Bonus for pointing out the multiple inheritance issue and how to deal with it! This is a better answer for scalability. – Brett Spencer May 02 '18 at 16:09
-
1Best solution in my opinion. From an architectural point of view it is scalable and maintainable. This is the correct way of doing this. I never liked ViewBag or ViewData..... They both seem hacky to me. – Jonathan Alfaro Feb 09 '19 at 21:01
this is pretty basic stuff, all you need to do is to create a base view model and make sure ALL! and i mean ALL! of your views that will ever use that layout will receive views that use that base model!
public class SomeViewModel : ViewModelBase
{
public bool ImNotEmpty = true;
}
public class EmptyViewModel : ViewModelBase
{
}
public abstract class ViewModelBase
{
}
in the _Layout.cshtml:
@model Models.ViewModelBase
<!DOCTYPE html>
<html>
and so on...
in the the Index (for example) method in the home controller:
public ActionResult Index()
{
var model = new SomeViewModel()
{
};
return View(model);
}
the Index.cshtml:
@model Models.SomeViewModel
@{
ViewBag.Title = "Title";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="row">
i disagree that passing a model to the _layout is an error, some user info can be passed and the data can be populate in the controllers inheritance chain so only one implementation is needed.
obviously for more advanced purpose you should consider creating custom static contaxt using injection and include that model namespace in the _Layout.cshtml.
but for basic users this will do the trick

- 4,687
- 1
- 32
- 25
-
-
1up and just want to mention that it also works with an interface instead of base class – VladL Feb 06 '18 at 10:11
Why dont you just add a new Partial View with i's own specific controller passing the required model to the partial view and finally Render the mentioned partial view on your Layout.cshtml using RenderPartial or RenderAction ?
I use this method for showing the logged in user's info like name , profile picture and etc.

- 119
- 1
- 2
-
3Can you elaborate on this please? I'd appreciate a link to some blog post that goes through this technique – J86 Feb 20 '17 at 23:44
-
1This can work but why take the performance hit? You have to wait for all the processing done by the controller, return the view, only to have the user's browser make ANOTHER request to get the data needed. And what if your Layout depends on the data to render appropriately. IMHO this is not an answer to this question. – Brett Spencer May 02 '18 at 16:05
old question but just to mention the solution for MVC5 developers, you can use the Model
property same as in view.
The Model
property in both view and layout is assosiated with the same ViewDataDictionary
object, so you don't have to do any extra work to pass your model to the layout page, and you don't have to declare @model MyModelName
in the layout.
But notice that when you use @Model.XXX
in the layout the intelliSense context menu will not appear because the Model
here is a dynamic object just like ViewBag
.

- 5,286
- 2
- 24
- 37
Maybe it isnt technically the proper way to handle it, but the simplest and most reasonable solution for me is to just make a class and instantiate it in the layout. It is a one time exception to the otherwise correct way of doing it. If this is done more than in the layout then you need to seriously rethink what your doing and maybe read a few more tutorials before progressing further in your project.
public class MyLayoutModel {
public User CurrentUser {
get {
.. get the current user ..
}
}
}
then in the view
@{
// Or get if from your DI container
var myLayoutModel = new MyLayoutModel();
}
in .net core you can even skip that and use dependency injection.
@inject My.Namespace.IMyLayoutModel myLayoutModel
It is one of those areas that is kind of shady. But given the extremely over complicated alternatives I am seeing here, I think it is more than an ok exception to make in the name of practicality. Especially if you make sure to keep it simple and make sure any heavy logic (I would argue that there really shouldnt be any, but requirements differ) is in another class/layer where it belongs. It is certainly better than polluting ALL of your controllers or models for the sake of basically just one view..

- 690
- 7
- 16
There is another way to archive it.
In the
BaseController
class create a method that returns a Model class like for instance.
public MenuPageModel GetTopMenu() { var m = new MenuPageModel(); // populate your model here return m; }
- And in the
Layout
page you can call that methodGetTopMenu()
@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>

- 36,338
- 80
- 323
- 498
From above only, but simple implementation
Index Page
@model CMS.Models.IndexViewModel
@{
ViewBag.PageModel = Model;
}
Layout Page
@{
var Model = (CMS.Models.IndexViewModel)ViewBag.PageModel;
}

- 9,489
- 8
- 74
- 87
-
2That's brilliant! one ViewBag to rule them all! I was at a point where I had about 6 ViewBag items in the layout. I just wondered about the casting - which is unavoidable I suppose. To me this is the simplest method. – Andy Oct 31 '22 at 09:12
Let's assume your model is a collection of objects (or maybe a single object). For each object in the model do the following.
1) Put the object you want to display in the ViewBag. For example:
ViewBag.YourObject = yourObject;
2) Add a using statement at the top of _Layout.cshtml that contains the class definition for your objects. For example:
@using YourApplication.YourClasses;
3) When you reference yourObject in _Layout cast it. You can apply the cast because of what you did in (2).

- 21
- 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; }
}
Use IContainsMyModel in your layout.
Solved. Interfaces rule.

- 29
-
1not sure why you were down-voted. Using an interface, similar to what you've done here, worked in my context. – boggy Apr 30 '18 at 23:27
For example
@model IList<Model.User>
@{
Layout="~/Views/Shared/SiteLayout.cshtml";
}
Read more about the new @model directive

- 1,084
- 6
- 11
-
But what if I want to pass the first element of collection to Layout model? – SiberianGuy Nov 11 '10 at 12:40
-
You have to fetch the first element in your controller and the set the model to @model Model.User – Martin Fabik Nov 11 '10 at 12:45
-
But I want my page to get IList and Layout - only the first element – SiberianGuy Nov 11 '10 at 12:55
-
If I have understood you right,you want the model to be a IList
and in the view get the first element of the collection ? If so the use @Model.First() – Martin Fabik Nov 11 '10 at 13:47 -
Can't you set View.FirstItem = model.First() in your razor code block, and then reference it in your view layout @View.FirstItem? – mikekidder Nov 15 '10 at 06:13
-
6The poster was asking about how to pass a model to the _Layout.cshtml page .. not the main view which uses the layout. – Pure.Krome Oct 16 '11 at 13:25