ASP.NET MVC Render Section on a Controller by Controller Basis - c#

This might not have an implemented answer but, I was searching for an easy way to render a section block on a controller basis. Obviously _ViewStart is not going to work because it won't know what view to render the section for, but to show you what I mean....
/Shared/_Layout.cshtml
...
#RenderSection("Streetcar", required: false)
...
/_ViewStart.cshtml
...
#{
Layout = "./Shared/_Layout.cshtml";
}
...
/Test/_ViewStart.cshtml
...
#{
// notice layout isn't being set because we still want the global _ViewStart layout
}
#section Streetcar {
Named Desire
}
...
In a perfect world, I could render a section by default for everything single view in the Test folder this way and catch all the views generated by the TestController Since it cannot be done this way, does anyone know of a way of doing this cleanly?

I'm not sure if I understand what you're asking by
Render Section on a Controller by Controller Basis
My answer is predicated on the assumption you just want Nested Master Pages.
So you're right, _ViewStart is a master page switch, not a layout/master page itself. But you can nest master pages:
/Shared/_Layout.cshtml
#RenderBody()
#RenderSection("scripts", required: false)
/_ViewStart.cshtml
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
/Views/Shared/_TestLayout.cshtml
#{
// References 'global' masterpage
Layout = "~/Views/Shared/_Layout.cshtml";
}
// And override it as necessary
#section scripts {
<script>
console.log("Nested layout ran");
</script>
}
#RenderBody()
/Test/_ViewStart.cshtml
#{
// Set test folder to use test master layout
Layout = "~/Views/Shared/_TestLayout.cshtml";
}

Related

what should I do with layout don't work when I change page?

I have layout and use this in two page and when i change page layout don't work
why this is happening?
Layout = "~/Views/Shared/_Layout.cshtml";
I use this code for pages
On the new page (a .cshtml file a.k.a a view in the MVC site architecture), make sure you have specified which layout you are using in an ASP.NET code block.
Such as:
#{
Layout = "_Layout";
}
the #{} is important in the above code. Also, if you haven't renamed the layout, you should just be able to write it as I specified, instead of having to do Layout = "~/Views/Shared/_Layout.cshtml";

Display ViewComponent in shared _Layout, only on certain pages

I have this ViewComponent in my shared layout:
#if (User.Identity.IsAuthenticated)
{
<vc:room></vc:room>
}
Is there a way to only have it render if the user is on a certain page, or exclude it from certain pages? Otherwise I'd just have to repeat it on every page that I need it to show?
There are multiple ways you could do this.
One way would be, in your _Layout.cshtml decide on a ViewBag property name and check if it exists and is set to true. I've called it ShowVC:
#if (User.Identity.IsAuthenticated && ViewBag.ShowVC is true)
{
<vc:room></vc:room>
}
In the views/pages you want to show the view component from the layout, in a code block, set ShowVC to true. For instance, if you want to show it in a view called Index.cshtml, do this:
Index.cshtml:
#model ModelClassName
#{
ViewBag.ShowVC = true;
}
Just skip this code block in the views where you do not want the view component to show.
This is exactly also the way the default application template uses(as of .NET 5) to display a different title for each view.
In _Layout.cshtml, you have:
<title>#ViewData["Title"] - AppName</title>
And the title for a specific view is set in a code block:
#model ModelClass
#{
ViewData["Title"] = "Title for the view"
}
For the most part, ViewBag and ViewData have only syntactic differences. For more on their differences, see this.
you can encapsulate the VC view component in partial views.
#if (User.Identity.IsAuthenticated && Model.HasAuthed)
{
<vc:room></vc:room>
}
when to call the partial view, pass the controlling model variable
<partial name="./AuthenticatedLayout.cshtml" model="#HasAuthed" view-data="ViewData"/>
there is a reference

Why does my Razor 'RenderSection' not get inherited by a grandchild view?

I'm setting up my ASP.NET Core site with a hierarchy of Razor views, which goes like this:
_Layout
_PanelLayout
Index
So, I have these files:
_ViewStart.cshtml
#{
Layout = "_PanelLayout";
}
_PanelLayout.cshtml
#{
Layout = "_Layout";
}
<div>Panel layout file</div>
#RenderBody()
_Layout.cshtml
<html><body>
<div>Main layout file</div>
#RenderBody()
#RenderSection("scripts", required: false)
</body></html>
Index.cshtml
#section scripts {
<script>
// test script
</script>
}
<div>Content view</div>
When I run a controller action that returns the Index view, I get the error:
InvalidOperationException: The following sections have been defined but have not been rendered by the page at '_PanelLayout.cshtml': 'scripts'.
Why doesn't Razor pick up the fact that the grandparent view of Index is rendering a 'scripts' section? If I remove the section, the layout works fine, so the only problem is this section rendering not carrying through to the grandparent layout. Is there a solution to this problem that still allows me to decide where I want to render the 'scripts' section on the grandparent layout ('_Layout') rather than the parent layout ('_PanelLayout')?
Any sections in parent layouts must be redefined in the child layouts or they will not be available further down the inheritance chain. In other words, in _PanelLayout.cshtml you need to add:
#section scripts
{
#RenderSection("scripts", required: false)
}
This gives a hook to the next level of layout or view referencing this layout (RenderSection) and then stuffs the output of that into the section in _Layout.cshtml.

Razor Section Definition

I am looking at some razor layout code. I have found the following snippet:
#section Foo
{
#if (#IsSectionDefined("Foo"))
{
#RenderSection("Foo", required: false)
}
}
Wouldn't #section Foo define Foo, meaning that the if (#IsSectionDefined("Foo")) condition would always be true? Also, if that section is defined in another view page, wouldn't this cause a redefinition?
Basically, I don't understand why this condition is wrapped in an #section clause.
I have figured out what this pattern is for: this is used in the situation where there are several layers of layouts. A section definition is scoped to the direct parent layout of a page. Therefore, to define a section that will be rendered in a higher level layout, one must pass it up the hierarchy using this construct.
You define the Sections in a Layout file with RenderSection("Foo");
So here is what I figured out:
The snipped of code doesn't hurt anything by itself.
What it says is this:
If you want to define a #section Foo, you have to define it in some other pages that has the current Layout page. And if you define it, you have to render it by adding #RenderSection("ExtraContent") in Layout page.
In Layout Page:
#section ExtraContent{
#if (#IsSectionDefined("ExtraContent")){
#RenderSection("ExtraContent", required: false)
}
}
#RenderSection("ExtraContent")
In About page:
#section ExtraContent{
<p>Some extra content</p>
}

Why does my .cshtml page need to define content?

Let's say I have the following structure in my ASP.NET MVC 3 application.
Items
Index.cshtml
Categories
Shared
_Index.cshtml
_Site.cshtml
Index.cshtml
Both Index.cshtml files use _Index.cshtml as the layout page and _Index is nested within the _Site layout.
Items/Index implements the optional sections defined in _Index. Shared/Index is empty.
The Items/Index view works fine. Since Categories doesn't have an Index, it uses the one in the Shared folder. This does not work.
It throws the error
The "RenderBody" method has not been called for layout page "~/Views/Shared/_Index.cshtml".
If _Site calls RenderBody, and _Index inherits from _Site, doesn't the content in _Index satisfy the required RenderBody call and Shared/Index.cshtml can be blank?
The reason I ask is because I have an ASP.NET MVC 1 application that implemented this structure using Master pages and it worked fine, but converting it to MVC 3 with Razor is causing this issue.
Here is the basic outline of what I'm describing:
_Site.cshtml
<!DOCTYPE html>
// head
<body>
#RenderBody()
</body>
_Index.cshtml
#{
Layout = "~/Views/Shared/_Site.cshtml";
}
<div id="sub-menu">
// Markup
</div>
// More markup
#RenderSection("SectionOne", required: false)
#RenderSection("SectionTwo", required: false)
Items/Index.cshtml (Working)
#{
Layout = "~/Views/Shared/_Index.cshtml";
}
#section SectionOne {
// Markup
}
Shared/Index.cshtml (RenderBody error)
#{
Layout = "~/Views/Shared/_Index.cshtml";
}
// Rest of this file is empty
I'm not sure i follow you completely, but ALL layout pages have to have a RenderBody(), even if they're nested. RenderBody() renders the content for the "child". When you have nested layout pages the nested layout is the child of the parent, and it's output must be rendered in the RenderBody. Likewise, the child of the child has to render it's body into the middle page.
To put it another way, anything that's not in a #section is considered the "body". So, _Index.cshtml needs to render it's body (Index.cshtml) and _Site.html has to render it's body (_Index.cshtml). It goes up the chain.
EDIT:
It appears that a layout has to render at least one section, be it with a RenderBody() or a RenderSection(). While it may be true that the sections are optional, rendering at least one section is not. Either add an empty section to your Index.cshtml or add a RenderBody() to your _Index.cshtml.

Categories