RenderSection() inside partial with master page

2020-06-30 13:59发布

问题:

I have a partial "Sidebar" added to the master page (Layout) and inside this partial I'm using:

@RenderSection("SearchList", required: false)

On one of the views that uses the master page I'm doing:

@section SearchList {
    // bunch of html
}

but it's giving me the error:

The file "~/Views/Shared/_SideBar.cshtml" cannot be requested directly because it calls the "IsSectionDefined" method.

What's wrong here?

回答1:

What you are trying to do is not currently supported in Razor. Sections only work between the view page and its immediate layout page.



回答2:

When creating your layout view you might want to put some pieces seperatly into partial views.

You might also encounter the need to render sections that need to be placed into the markup of one of these partial views. However, since partial views do not support RenderSection logic you'll have to work around this.

You can render sections in a partial views by passing the RenderSection result from your Layout page as the model of the partial view. You can do this by putting this line of code in your _Layout.cshtml.

_Layout.cshtml

@{ Html.RenderPartial("_YourPartial", RenderSection("ContextMenu", false));}

Then in _YourPartial.cshtml you can render the section passed along as the model in the Html.RenderPartial call on the _Layout view. You check if the model is null just in case your section is not required.

_YourPartial.cshtml

@model HelperResult
@if (Model != null)
{
    @Model
}


回答3:

It is possible to solve this with razor helpers. It's kinda elegantly-hacky™ but it did the job for me.

So in a parent view you define a helper:

@helper HtmlYouWantRenderedInAPartialView()
{
    <blink>Attention!</blink>
}

Then when you render partial, you pass this helper to it

@Html.Partial("somePartial", new ViewDataDictionary { { "OptionalSection1", (Func<HelperResult>)(HtmlYouWantRenderedInAPartialView) } })

Then inside a partial view you call this helper like so

<div>@ViewData.RenderHelper("OptionalSection1")</div>

Finally you need to have this extension method to simplify the "calling" part

public static HelperResult RenderHelper(this ViewDataDictionary<dynamic> viewDataDictionary, string helperName)
{
    Func<HelperResult> helper = viewDataDictionary[helperName] as Func<HelperResult>;
    if (helper != null)
    {
        return helper();
    }

    return null;
}

So the whole point is to pass a delegate of this helper and then when the child view calls it, the contents get rendered where you want them.

The end result of a child view would look like this

<div><blink>Attention!</blink></div>