3

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')?

Jez
  • 27,951
  • 32
  • 136
  • 233
  • Weirdly enough I ran into this exact issue on Friday. Can't wait to see how it's resolved so that I can properly use my layout pages. – gilliduck Sep 16 '19 at 15:21
  • 1
    You should check out this question and see if it helps https://stackoverflow.com/q/7602432/6158454 – Patrick Mcvay Sep 16 '19 at 15:41

1 Answers1

8

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.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • Yes, I tried that and it worked. Still beats me why the Razor engine can't do this automatically though. It would be intuitive. – Jez Sep 16 '19 at 15:48
  • Not necessarily. The way this works is that the view only sees sections defined directly by the layout it references. This setup allows you to hide intermediate sections, which I've actually used a number of times. Let's say for example that I want to allow a sub layout to modify a particular area of the page, but I *don't* want to allow a view to. I simply don't redefine that section in the sub layout. It gives you a lot of power actually. – Chris Pratt Sep 16 '19 at 15:51