ASP.NET Core: Section Scripts in a Partial View

A @section Scripts block does not work when placed in a partial view in ASP.NET Core, which is the same functionality as in ASP.NET MVC. Unfortunately, you don’t get any error messages if you try to add the section to a partial — it just does nothing. In many cases, having a scripts section in a partial view would be an anti-pattern, since the partial can be rendered an unknown number of times. However, there are times when I believe a scripts section is warranted in a partial, particularly when you’re trying to create dynamic JavaScript based on the model passed into the partial view. While you can’t just use the actual @section Scripts in a partial view, you can add some HTML helper extensions to accomplish the same thing.

Below is the code to accomplish this functionality — here are the helper extension methods that you’d add into a C# file in your project:

using System;
using System.Linq;
using System.Text.Encodings.Web;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Rendering;
public static class HtmlHelperExtensions
{
    private const string _partialViewScriptItemPrefix = "scripts_";
    public static IHtmlContent PartialSectionScripts(this IHtmlHelper htmlHelper, Func<object, HelperResult> template)
    {
        htmlHelper.ViewContext.HttpContext.Items[_partialViewScriptItemPrefix + Guid.NewGuid()] = template;
        return new HtmlContentBuilder();
    }
    public static IHtmlContent RenderPartialSectionScripts(this IHtmlHelper htmlHelper)
    {
        var partialSectionScripts = htmlHelper.ViewContext.HttpContext.Items.Keys
            .Where(k => Regex.IsMatch(
                k.ToString(),
                "^" + _partialViewScriptItemPrefix + "([0-9A-Fa-f]{8}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{4}[-][0-9A-Fa-f]{12})$"));
        var contentBuilder = new HtmlContentBuilder();
        foreach (var key in partialSectionScripts)
        {
            var template = htmlHelper.ViewContext.HttpContext.Items[key] as Func<object, HelperResult>;
            if (template != null)
            {
                var writer = new System.IO.StringWriter();
                template(null).WriteTo(writer, HtmlEncoder.Default);
                contentBuilder.AppendHtml(writer.ToString());
            }
        }
        return contentBuilder;
    }
}

PartialSectionScripts is called in the partial view in place of where you would otherwise be using @section Scripts.

RenderPartialSectionScripts would typically be called in your shared layout, e.g. _Layout.cshtml in the standard scaffolded projects, and will render any scripts added in partials via the PartialSectionScripts method call.

Here’s an example from a partial view of using PartialSectionScripts:

@Html.PartialSectionScripts(
    @<script>
        alert('Hello from the partial view!');
    </script>
)

And the example with the RenderPartialSectionScripts line added in your shared layout, where you would likely want to place it after your RenderSection and before the end of the body:

    @*...*@
    @RenderSection("Scripts", required: false)
    @Html.RenderPartialSectionScripts()
</body>
</html>