1

note: <!-- [..] --> represents excluded code for clarity


With a _Layout as follow

<!-- [..] -->
    @Html.EmitRequiredStylesheet()
</head>
<body>
    @await Html.PartialAsync("_Header");
    <div class="container body-content">
        @RenderBody()
    </div>
    @await Html.PartialAsync("_Footer");
<!-- [..] -->

a _Footer partial containing the following code

<!-- [..] -->
@Html.RequireStylesheet("/css/Footer.css")
<!-- [..] -->

And RequireStylesheet()aswell as EmitRequiredStylesheet() being two extension methods that I adapted to .Net Core 2.0 from this post as follow

    public static string RequireStylesheet(this IHtmlHelper html, string path, int priority = 1)
    {
        var contextItems = html.ViewContext.HttpContext.Items;
        var requiredScripts = contextItems["RequiredStylesheets"] as List<ResourceInclude> ?? new List<ResourceInclude>();

        if(requiredScripts.All(i => i.Path != path))
            requiredScripts.Add(new ResourceInclude() {Path = path, Priority = priority});

        return null;
    }

    public static HtmlString EmitRequiredStylesheet(this IHtmlHelper html)
    {
        var contextItems = html.ViewContext.HttpContext.Items;

        if(!(contextItems["RequiredStylesheets"] is List<ResourceInclude> requiredScripts))
            return null;

        var sb = new StringBuilder();
        foreach(var item in requiredScripts.OrderByDescending(i => i.Priority))
        {
            sb.Append($"<link ref=\"{item.Path}\" type=\"stylesheet\" />\n");
        }

        return new HtmlString(sb.ToString());
    }

What I'm trying to do here is to have a partial view be capable of telling the _Layout which stylesheets/scripts it needs. As this answer explains it the Razor parse order means that the layout will be parsed last. But from the answer I expected my _Footer partial view to be parsed and exectued before the _Layout itself, which it is not. Debugging using breakpoints revealed that the @Html.EmitRequiredStylesheet() call is made before the @Html.RequireStylesheet("/css/Footer.css") call which means that the stylesheet isn't registered yet when the first one is called.

This code would work perfectly if the _Footer partial was called from the code rendered by the @RenderBody() but it is not (it's part of the layout).

Is there any workaround such as a way to tell razor that a given partial must executed before the layout itself ?

Note: even tho it would make sense to include the style sheet directly into the _Layout I'd like to have it be as close as possible to the code it's related to. I'm really not a big fan of massive centralised config files and I prefer having my includes/config be done as close to the code as possible

Mathieu VIALES
  • 4,526
  • 3
  • 31
  • 48
  • I could be mistaken but I believe razor generates your page in the following order: 1. `RenderBody()` executed top to bottom, partial views in the order they appear 2. `_Layout` executed top to bottom, inserting the results of `RenderBody()` where it should. E: - To do what you want you'd likely have to build some custom delayed render functions and at the end of your layout page do `ExecuteDelayedRenders()` – Neil Nov 01 '17 at 14:51
  • So i don't have any built-in ways of doing this ? Hmm okay, thanks. I'll try to do it the way you advised. Thanks. – Mathieu VIALES Nov 01 '17 at 15:14

0 Answers0