Sharing a single _ViewStart across areas in ASP.NET MVC
When using Areas in MVC it’s a common desire to want to use a single layout template for all views. To easily assign a layout template the most common approach is to use a ~/Views/_ViewStart.cshtml (or .vbhtml) in the parent directory of the views. The problem is that when using areas, the ~/Views/_ViewStart.cshtml is not in a parent directory because areas are located in ~/Areas (a sibling of ~/Views). This means the ~/Views/_ViewStart.cshtml is not considered for assigning a default layout template for views within areas.
One solution commonly suggested is to put a _ViewStart.cshtml in the views directory inside the area, but this becomes tedious since you need to do it for each area, as such:
So the obvious approach is to place the _ViewStart.cshtml in the root folder of the entire project. The only problem is that when you create ~/_ViewStart.cshtml and then run the application you end up with this compilation error:
In its wonderful eloquence, this is explaining that you’re using a .cshtml file in MVC and not in WebMatrix. The issue here is that Razor is used in two contexts: 1) MVC and 2) WebMatrix. WebMatrix is the other development framework and tooling under the “One ASP.NET” and it uses Razor as its syntax for mixing markup and code to emit HTML pages dynamically (so in a sense the modern replacement for classic ASP).
So our problem is that we need to tell the ASP.NET compiler to compile this in the context of MVC. This is simple – the same razor configuration that was in ~/Views/web.config simply needs to be moved (or copied) out to the top-level ~/web.config (so the <configSections> and the <system.web.webPages.razor> elements):
And that’s it. You can now have a single ~/_ViewStart.cshtml that assigns a default layout template for all your views (both inside and outside areas).
Oh except for one problem. If you create the top-level ~/_ViewStart.cshtml and run the application prior to copying the configuration values in ~/web.config you might still get the same error from before:
Type ‘ASP._Page__ViewStart_cshtml’ does not inherit from ‘System.Web.WebPages.StartPage’.
The issue here is that once the ~/_ViewStart.chtml has been compiled by the ASP.NET runtime the assembly is cached and not re-compiled when the ~/web.config is changed. The simple fix is to make the changes in ~/web.config and then open and save ~/_ViewStart.chtml. Updating the timestamp on ~/_ViewStart.chtml triggers a recompile but now with the updated settings in ~/web.config.
Here’s a sample project that illustrates this working: http://sdrv.ms/PSTHKk
Trackbacks
- Missing Layout in ASP.NET MVC Area’s Views | Joey Li's IT Zone
- digitalLighthouse .Net | MVC.NET RAZOR Engine – Common View
- ASP.NET MVC Architecture (Part I): Giving your Project Structure with Areas and Services | FabianGosebrink
- ASP.NET MVC Architecture (Part I): Giving your project structure with Areas and Services | Offering Solutions
Thanks alot!
Made my day =)
Thank you so much for helping!!!!!!
The hint with updating the timestamp on ~/_ViewStart.chtml was my rescue :) Thanks a lot!
Hello, Great write up! I know at this point that you published this a few years ago but I am facing an issue that I can’t seem to resolve. I followed the steps you have outlined but am still facing the issue and was hoping that you might be willing to point me in the right direction. I have a Asp.net (4.5) MVC 5 (Razor) application (C#) which only has one area which we use for user data management, we needed to give the user the ability to maintain records (Create/Retrieve/Update/Delete) from a few specific tables so we created a separate web application using the Dynamic Data Entities Web Application template and moved this into a separate Area of our application. The views all use a shared layout which is not located in the Area. This all worked fine until we implemented a database driven roles based menu. We have 2 layout files, _rootLayout.cshtml which is simply a content splitter for the header and content area, then the second layout _mainLayout.cshtml uses a content splitter for the LeftPane which is where our database driven roles based navigation menu gets loaded and a RightPane which is used as an actions menu for certain views. Before we implemented the roles base navigation menu in _mainLayout.cshtml we used @RenderSection(“LeftPane”) etc.. Because we needed to get data to create the navigation menu to only show the user the resources they have access too we switched this to Html.RenderAction(“LeftNavigationMenu”, “Navigation); Everything in the main application works perfectly, but now nothing in the one Area we have works, the error is.. “Execution of the child request failed. Please examine the InnerException for more information.” The inner exception says, “The controller for path ‘/DomainTables/SubjectDefinitions’ was not found or does not implement IController.”.. The controller path mentioned is for the area we have to manage user data and all of this worked before the navigation menu. Its almost like the Action is firing and after it completes it is trying to load the area into the content area but it does not expect it to be in the Area, it expects it to be where the rest of the application exists. If you could shed any light on this or point me in the right direction I would create appreciate it.
Thank You,
Patrick Shaffer
Not sure — Html.RenderAction — does it allow you to indicate a the controller? Also, if it’s in an area, you need to indicate that via a route param of “area”.