C#/MVC Wrap View with Partial? - c#

Is it possible to wrap a view with a partial file? Sort of like a layout, but with a partial?
For example:
Layout
<html>
...
<body>
<div>#RenderBody</div>
</body>
</html>
View
#{
Layout = "~/Views/Shared/_PartialWrapper.cshtml";
}
<!--content I want to wrap with partial-->
<div class='alert alert-info'>HELLO WORLD</div>
Partial
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div style='border:1px solid #cccccc;'>
<div style='background-color:black;color:white;'>
StackOverflow Rocks
</div>
<div>
#RenderBody
</div>
</div>
When I tried the above scenario, I get an error on the partial file on the "#RenderBody" line. The error:
The best overloaded method match for 'System.Web.WebPages.WebPageExecutingBase.Write(System.Web.WebPages.HelperResult)' has some invalid arguments
Is there a better way to do this -- or make the above work?

As #Overmachine mentioned, RenderBody is a Method so you need to write #RenderBody() like so:
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div style='border:1px solid #cccccc;'>
<div style='background-color:black;color:white;'>
StackOverflow Rocks
</div>
<div>
#RenderBody()
</div>
</div>

Related

Blazor Layout = null

Please, I need a way to master Blazor multi-layered layouts, but for now, I desperately need to know how to null layouts so that I can add everything from `
<html>
to
</html>
`
myself on the #page directly.
Why do I want to do this?
in MVC I can make the ViewModel inherit from the _layout ViewModel so that I can dynamically add user images, name, properties... in the navigation and side-nav, even hide some nav options. like in the picture below.
Looks like you want to custom your MainLayout?
You can just clear it, open MainLayout.razor (where the _Layout lies) and only add #Body in it:
#inherits LayoutComponentBase
#Body
From your example, seems you just want to custom your NavMenu?
It's the same,open NavMenu.razor and just modify the navs.
And for extension, if you want to different types of Layout, you can use NavigationManager to
check the parameter in your url and it will use the related Layout, like:
#inherits LayoutComponentBase
#inject NavigationManager _navManager
#if (_navManager.Uri.Contains("CustomLayout1"))
{
#Body
}
else
{
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<div class="main">
<div class="top-row px-4">
About
</div>
<div class="content px-4">
#Body
</div>
</div>
</div>
}
So if the page is #page "/CustomLayout1/counter" Then it will use your null MainLayout in this demo.
I think you want multiple layouts.
The base file (_Host.cshtml for blazor server side or index.html for WASM), needs to be as empty as possible to only have and
For _Host.cshtml, you probably need to do something like:
#page "/"
#namespace YOURNAMESPACE.Pages
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#{
Layout = null;
}
<html>
<component type="typeof(App)" render-mode="ServerPrerendered" />
</html>
For index.html, something like:
You can read more here: https://learn.microsoft.com/en-us/aspnet/core/blazor/layouts?view=aspnetcore-5.0

How to separate #RenderBody() into two parts

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

Correct usage of microdata itemscopes in combination with asp.net mvc

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.

MVC - Nested Partial Views

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().

Nested layouts for MVC5

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.

Categories

Resources