I've seen a few posts on this topic:
Razor Nested Layouts with Cascading Sections
MVC 3 - Nested layouts - sections don't render in Areas
And it always seems to be problematic. However they are both pretty old so wondering if things have changed.
Basically I have a master layout, and 3 different body templates based on what kind of page it is. For examples sake:
_Layout.cshtml
<html lang="en">
<head>
</head>
<body style="padding: 50px 0;">
<header class="navbar navbar-default navbar-fixed-top" role="banner">
#Html.Partial("_MenuPartial")
</header>
<ol class="breadcrumbs">
#RenderSection("breadcrumbs", true);
</ol>
<section>
#RenderBody();
</section>
<footer class="navbar navbar-default navbar-fixed-bottom">
#Html.Partial("_FooterPartial")
</footer>
#Html.Partial("_ScriptInitPartial")
</body>
</html>
_LayoutForEdit.cshtml
<div class="panel panel-primary">
<div class="panel-body">
<div class="col-lg-2">
<ul class="nav nav-pills nav-stacked">
#RenderSection("tabs", true)
</ul>
</div>
<div class="col-lg-10">
<div class="tab-content">
#RenderBody()
</div>
</div>
</div>
<div class="panel-footer">
<button class="btn btn-primary" data-bind="enable: Entity.isValid, click: save">Save</button>
</div>
</div>
Now this renders fine when called. Almost.
The rendering of sections must be in the child layout it seems. If I try to put the breadcrumbs in the _Layout.cshtml, it will fail because _LayoutForEdit.cshtml never rendered it. How can I fix this?
The following sections have been defined but have not been rendered for the layout page "~/Views/Shared/_LayoutForEdit.cshtml": "breadcrumbs".
I know it's an old question. I thought I'd share this anyway in case anyone else runs into this (like I did).
At the bottom of your child layout, you define a section with the same name as the section in the parent layout. Inside of this section you simply put a #RenderSection, again specifying the same name as before. Once this is in place, you essentially have the child layout "bypass" content from pages, up to its parent layout:
#section breadcrumbs {
#RenderSection("breadcrumbs", true)
}
Not sure if you still need help, but I'll answer anyways.
There RenderSection method takes the following parameters according to the
MSDN Documentation:
public HelperResult RenderSection(
string name,
bool required
)
Parameters
name
Type: System.String
The section to render.
required
Type: System.Boolean
true to specify that the section is required; otherwise, false.
Change the call to:
#RenderSection("breadcrumbs", false);
If the section "required" parameter is false, it will not give an error if that section is not included by a view.
Related
Im using ASP.NET Core 2.2. The problem that I have is I don't know where to use
#RenderBody() in my _Layout page. This is representation of what I want to do:
The green parts should come from _Layout and white parts coming from HomePage.cshtml. My HomePage consists of two parts a slider and a list of content below it.This is what I tried, but it doesn't meet my need because i can't put slider in it.
this is _Layout
<html>
<body>
<main>
<header></header>
<div class="left-col">
<div class="content">#RenderBody()</div>
<div class="right-col">
<footer></footer>
</main>
</body>
</html>
You can define a section in the layout to render the desired content
HomePage.cshtml
#{
ViewBag.Title = "Home Page";
}
#section Slider {
<div>My HomePage slider</div>
}
<p>My HomePage content</p>
The layout would check to see if the section exists and render it if it does
_Layout.cshtml
<html>
<body>
<main>
<header></header>
#if (IsSectionDefined("Slider")) {
<div class="homepage-slider">
#RenderSection("Slider", required: false)
</div>
}
<div class="left-col">
<div class="content">#RenderBody()</div>
<div class="right-col">
<footer></footer>
</main>
</body>
</html>
You would obviously have to specify what ever styling needed to position the section where desired.
Reference Layout in ASP.NET Core: Sections
Because I'm using asp.net MVC the views are rendered in my body using #RenderBody()
My question is: am I correctly using the schema.org microdata?
In my example I have the html which is WebSite, it has some meta data in the header for WebSite itemscope.
Next I set the mainEntityOfPage to WebPage and add header, footer.
Some pages that will apear in the #RenderBody() have an own scope (e.g. ContactPage) and other have just data with some itemscopes of Product or Place.
Is this the correct way of using microdata?
Simplified _Layout.cshtml
<!DOCTYPE html>
<html itemscope itemtype="http://schema.org/WebSite">
<head prefix="og: http://ogp.me/ns#">
<meta property="og:title" content="test">
<meta itemprop="about" content="test">
</head>
<body itemprop="mainEntityOfPage" itemscope itemtype="http://schema.org/WebPage">
<div class="myheader" itemscope itemtype="http://schema.org/WPHeader">
<div class="...">
<nav class="navbar navbar-default navbarwrapper" itemscope itemtype="http://schema.org/SiteNavigationElement">
#*...*#
</div>
</div>
</div>
#RenderBody()
<div>
#* some other stuff*#
</div>
<div class="myfooter" itemscope itemtype="http://schema.org/WPFooter">
#*...*#
</div>
</body>
Simplified Index.cshtml (Home) which is shown in the #RenderBody(), and thus in the WebPage itemscope without any other itemscopes:
<div class="...">
#* content *#
</div>
Simplified Contact.cshtml (Home) which is shown in the #RenderBody(), and thus in the WebPage itemscope with other scopes:
<div class="banner">
#* banner stuff *#
</div>
<div class="myMiddleContent" itemscope itemtype="http://schema.org/ContactPage">
<div class="container">
<div class="row">
#*...*#
<div class="col-md-6" itemscope itemtype="http://schema.org/Place">
#*...*#
</div>
</div>
</div>
</div>
UPDATE:
This is what i have now:
<!DOCTYPE html>
<html itemscope itemtype="http://schema.org/WebSite">
<head prefix="og: http://ogp.me/ns#">
<meta property="og:title" content="test">
<meta itemprop="about" content="test">
<meta itemprop="headline" content="my fancy pancy site">
<meta itemprop="cool, things here">
</head>
<body itemprop="mainEntity" itemscope itemtype="http://schema.org/ContactPage"> #* or /WebPage *#
<div class="myheader" itemprop="hasPart" itemscope itemtype="http://schema.org/WPHeader">
<div class="...">
<nav class="navbar navbar-default navbarwrapper" itemprop="hasPart" itemscope itemtype="http://schema.org/SiteNavigationElement">
#*...*#
</div>
</div>
</div>
#* injected via #RenderBody() *#
<div class="banner">
#* banner stuff *#
</div>
<div class="myMiddleContent">
<div class="container">
<div class="row">
#* list of products...*#
<div class="col-md-6" itemscope itemtype="http://schema.org/Product">
#*product x...*#
</div>
<div class="col-md-6" itemscope itemtype="http://schema.org/Product">
#* product y...*#
</div>
</div>
</div>
</div>
<div itemprop="contentLocation" itemscope itemtype="http://schema.org/Museum">
<link itemprop="additionalType" href="http://schema.org/TouristAttraction">
<meta itemprop="name" content="Foo bar">
<meta itemprop="sameAs" content="http://www.facebook.com/FooBar">
<div itemprop="openingHoursSpecification" itemscope itemtype="http://schema.org/OpeningHoursSpecification">
#*...*#
</div>
</div>
#* end of injected via #RenderBody() *#
<div>
#* some other stuff*#
</div>
<div class="myfooter" itemprop="hasPart" itemscope itemtype="http://schema.org/WPFooter">
#*...*#
</div>
#*website/webpage creator / author / etc... *#
<div itemprop="creator" itemscope itemtype="http://schema.org/LocalBusiness">
<meta itemprop="name" content="...">
#*...*#
</div>
<div itemprop="copyrightHolder" itemscope itemtype="http://schema.org/LocalBusiness">
#*...*#
</div>
</body>
</html>
As Index.cshtml has no schema markup within, I'll talk about Contact.cshtml when inserted in _Layout.cshtml. This applies to Index.cshtml except when referring to content in Contact.cshtml.
The schema markup is read as follows:
WebSite
mainEntityOfPage: WebPage
WPHeader
SiteNavigationElement
ContactPage
Place
WPFooter
There are a number of problems with the markup, including but not limited to the lack of hierarchical organisation of the items on the page and incorrect schema.org usage. I will discuss your code line by line below:
<!DOCTYPE html>
<html itemscope itemtype="http://schema.org/WebSite">
This markup informs that the HTML on this page is a web site. This is fine, but may not be what you intend. Terminology is important with schema markup — perhaps this should be a WebPage instead? I'll come back to this later.
<head prefix="go: http://ogp.me/ns#">
<meta property="og:title" content="test">
<meta itemprop="about" content="test">
</head>
<body itemprop="mainEntityOfPage" itemscope itemtype="http://schema.org/WebPage">
Here you're stating that the WebSite is the mainEntityOfPage: WebPage. This is almost certainly not what you intended. To clarify, you're saying the WebPage (this single page) mainEntity (the main content of this single page) is WebSite (the entire site). I encourage you to check schema.org/mainEntityOfPage for the specification of this property. Here's what I would do instead:
<!DOCTYPE html>
<html>
<head prefix="og: http://ogp.me/ns#">
<meta property="og:title" content="test">
<meta itemprop="about" content="test">
</head>
<body itemscope itemtype="http://schema.org/WebPage">
Removing the itemprop removes the link from the WebPage to the WebSite and as you're not using any WebSite properties the WebSite schema can be removed.
<div class="myheader" itemscope itemtype="http://schema.org/WPHeader">
<div class="...">
<nav class="navbar navbar-default navbarwrapper" itemscope itemtype="http://schema.org/SiteNavigationElement">
#*...*#
</div>
</div>
</div>
These are two completely separate schemas. They are not associated with each other, nor with the WebPage schema. You're missing the itemprop attribute on both these. Both of them should include itemprop="hasPart" to define the following hierarchy:
WebPage
hasPart: WPHeader
hasPart: SiteNavigationElement
<div class="banner">
#* banner stuff *#
</div>
<div class="myMiddleContent" itemscope itemtype="http://schema.org/ContactPage">
This is a bit difficult, because ContactPage is a WebPage, but you're already in the scope of a WebPage and it's not a different page as such. Usually you would link these two with itemprop="mainEntity" but the item type is a WebPage, so this is incorrect. mainContentOfPage is for WebPageElement, but again you've defined an entire page.
This is where the WebPage schema should be replaced with ContactPage, but I understand that your ‘drop-in’ to #RenderBody() doesn't accommodate this. I guess mainEntity is the best you can do if you can't change the WebPage schema based on which page you're inserting (WebPage is still the most appropriate schema for Index.cshtml). If you are able to change the layout page when inserting the contact page, you should change the WebPage to ContactPage, and not use mainEntity. As the schema in the contact page as discussed later applies to the ContactPage schema, you do not need to make any further changes later.
The schema so far, presuming you are unable to change the layout page when inserting the contact page, is the following:
WebPage
hasPart: WPHeader
hasPart: SiteNavigationElement
mainEntity: ContactPage
<div class="container">
<div class="row">
#*...*#
<div class="col-md-6" itemscope itemtype="http://schema.org/Place">
This Place is completely separate from anything so far — again, an itemprop is missing from this schema. Use contentLocation (or define an Organization/etc to contain the Place). Then, you'll end up with…
WebPage
hasPart: WPHeader
hasPart: SiteNavigationElement
mainEntity: ContactPage
contentLocation: Place
#*...*#
</div>
</div>
</div>
</div>
<div>
#* some other stuff*#
</div>
<div class="myfooter" itemscope itemtype="http://schema.org/WPFooter">
Like WPHeader, WPFooter is missing hasPart. The finished schema looks like this:
WebPage
hasPart: WPHeader
hasPart: SiteNavigationElement
mainEntity: ContactPage
contentLocation: Place
hasPart: WPFooter
If you are able to change the layout page when inserting the contact page, the schema looks like this:
ContactPage
hasPart: WPHeader
hasPart: SiteNavigationElement
contentLocation: Place
hasPart: WPFooter
The corrected code (including fixing <nav></div>) is as follows:
<!DOCTYPE html>
<html>
<head prefix="og: http://ogp.me/ns#">
<meta property="og:title" content="test">
<meta itemprop="about" content="test">
</head>
<body itemscope itemtype="http://schema.org/WebPage">
<div class="myheader" itemprop="hasPart" itemscope itemtype="http://schema.org/WPHeader">
<div class="...">
<nav class="navbar navbar-default navbarwrapper" itemprop="hasPart" itemscope itemtype="http://schema.org/SiteNavigationElement">
#*...*#
</nav>
</div>
</div>
#RenderBody()
<div>
#* some other stuff*#
</div>
<div class="myfooter" itemprop="hasPart" itemscope itemtype="http://schema.org/WPFooter">
#*...*#
</div>
</body>
<div class="banner">
#* banner stuff *#
</div>
<div class="myMiddleContent" itemprop="hasPart" itemscope itemtype="http://schema.org/ContactPage">
<div class="container">
<div class="row">
#*...*#
<div class="col-md-6" itemprop="contentLocation" itemscope itemtype="http://schema.org/Place">
#*...*#
</div>
</div>
</div>
</div>
Google Structured Data Testing Tool won't show this correctly as some items are missing content.
Question background:
I have a MVC site that implements BootStrap. Currently each page is based on a MasterLayout view page. This master contains a dropdown list that will be populated with the cart items in the sites shopping cart along with the carts total monetary value. Please note currently the details in the dropdown are fixed values in the HTML:
What I'm after:
I've tried searching for this but cant seem to find exactly the answer. I want to be able to populate the dropdown in the navbar with the cart contents each time a page is loaded. To do this I need a method to extract the cart item objects which are stored in a SESSION object variable. Currently my MasterLayout view is just that, its a view that has no controller associated with it.
How do I go about assigning some sort of method to my MasterLayout so I can pass the cart items model to the view which in-turn will be set to the dropdown each time the page is loaded?.
Here's the HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
#Styles.Render("~/Content/bootstrap.css")
#Styles.Render("~/Content/Styles.css")
#Scripts.Render("~/bundles/modernizr")</script>
</head>
<body>
<div class="navbar navbar-fixed-top">
<nav class="navbar navbar-default" role="navigation" id="nav">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand logo">HS<b>WH</b></a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li>Products</li>
<li>About Us</li>
<li>Contact</li>
</ul>
<form class="navbar-form pull-right">
<input type="text" class="form-control" placeholder="Search this site..." id="searchInput">
<button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-search"></span></button>
</form>
<form class="navbar-form pull-right">
<div class="btn-group btn-group-cart">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
<span class="pull-left"><i class="fa fa-shopping-cart icon-cart"></i></span>
<span class="pull-left">Shopping Cart: 2 item(s)</span>
<span class="pull-right"><i class="fa fa-caret-down"></i></span>
</button>
<ul class="dropdown-menu cart-content" role="menu">
<li>
<a href="detail.html">
<b>Penn State College T-Shirt</b>
<span>x1 $528.96</span>
</a>
</li>
<li>
<a href="detail.html">
<b>Live Nation ACDC Gray T-Shirt</b>
<span>x1 $428.96</span>
</a>
</li>
<li class="divider"></li>
<li>Total: $957.92</li>
</ul>
</div>
</form>
</div>
</div>
</nav>
</div>
#RenderBody()
<footer>
<div class="container">
<div class="row">
<div class="col-sm-12 textAlignCenter">
<h5>Copyright © 2014 - Test Site</h5>
</div>
</div>
</div>
</footer>
<script>
$(document).ready(function () {
$('.dropdown-toggle').dropdown('toggle')
});
</script>
</body>
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
#RenderSection("scripts", required: false)
</html>
I would probably do this using a child action invoked from the master layout.
#Html.Action("Cart")
On server side create action returns PartialViewResult, which render your cart model.
At front-end render your partial via #Html.Action("YourPartialCart",'CartController') or ajax call.
All Views have a controller associated with them because the views are inherits. E.g. when you create a view you set it's Layout to be equal to the master.cshtml file.
Your view has a Model associated with it.
You can tackle this a couple of ways.
The simplest would be to use something like HttpContext.Current.Items, which is a request unique collection of shared data accessible from anywhere during an HttpRequest.
The next would be to use inheritance on your models. For example, Create Models like this
MasterModel
-> CartPageModel (inherits MasterModel)
-> AccountSettingsModel (inherits MasterModel)
etc.
Then on your master page set the model to MasterModel via the #Model MasterModel code, and on your view it would be #Model CartPageModel.
In your controller the code will populate values on the base model MasterModel and it's derrived type CartPageModel.
I am getting an error ("Server Error in '/' Application") when I nest partial views in my MVC app. The views work fine individually, but not when nested. It's my understanding that it's okay to do this, so what am I doing wrong?
Essentially, I am trying to use partials as sub-layouts within my _Layout.cshtml.
Here's my main layout - _Layout.cshtml
<!DOCTYPE html>
<html>
<head>...</head>
<body style="padding-top: 80px;">
<div class="container-fluid">
<div class="row">
<div id="myTab" class="col-lg-12 col-md-12 col-sm-12">
...
<div class="tab-content">
<div class="tab-pane fade" id="search">
#Html.Partial("~/Areas/Search/Views/Shared/_SearchLayout.cshtml")
</div>
</div>
</div>
</div>
</div>
#RenderBody()
#RenderSection("scripts", required: false)
</body>
</html>
This is the first partial view (_SearchLayout). If I remove the partials AND #RenderBody, no error.
<div class="container-fluid">
#Html.Partial("_PolicySearch")
#Html.Partial("_ClaimSearch")
</div>
#RenderBody()
This partial view is nested in the first partial view (_SearchLayout):
<div class="row top-buffer search-outline form-horizontal">
<div class="col-md-1 search-icon-size text-primary">
<i class="glyphicon glyphicon-heart"></i>
</div>
<div class="col-md-1 search-icon-size text-primary">
<h4>Claim Search</h4>
</div>
</div>
In your first partial view:
Remove RenderBody
Replace Html.Partial to Html.RenderPartial
I also would recommend to rename your partial view to something not containing the word "Layout" to avoid the mismatch between the view types.
Use Html.RenderPartial instead
The problem is #RenderBody(). This can only be called in a layout, which when used in this way _SearchLayout.cshtml is not, despite its name.
The important thing to remember about layouts, partials and views in ASP.NET MVC is that they're all views. The only thing that differentiates them is how they're used. In this instance, you're using the _SearchLayout.cshtml view as a partial, and partials can't use #RenderBody().
I've created a section for a footer in my asp.net MVC 3 Web Application:
<footer>
#RenderSection("Footer", true)
</footer>
This footer will be the same on every page, so it doesn't make sense for me to define it for each and every view. So, is there any way I can globally declare this footer section for all views? The footer will contain code so as far as I know it's bad practice, if not impossible, to directly define it in the .cshtml file.
Thank you in advance.
I have handled the same scenario by creating a partial view "_Footer" and place it on the "_Layout".
#ViewBag.Title
#Html.Partial("_Header")
<div id="content">
<div id="nav-bar">
#Html.Partial("_Menu")
</div>
<div class="container">
#RenderBody()
</div>
</div>
<div id="footer">
#Html.Partial("_Footer")
</div>
#Html.Partial("_Scripts")
Sure:
<footer>
#if (IsSectionDefined("footer"))
{
#RenderSection("footer")
}
else
{
... put your default footer here
}
</footer>
And in views that you want to override the footer simply define the section.
You can place the footer in your SiteLayout.cshtml. See this article for more information on using layouts with MVC 3.