You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kentico 13:PartialWidgetPage中HtmlHelper扩展无法写入_Layout.cshtml

问题描述

我正在使用PartialWidgetPage重现旧版Kentico的MasterPage功能,导航(Nav)和页脚(Footer)能正常渲染到_Layout.cshtml中,但页面内的某个组件/小部件出现问题:该部件通过自定义HtmlHelper扩展,以类似@RenderSection()的方式向_Layout.cshtml写入内容,在普通页面中可正常工作,但当它位于由PartialWidgetPage渲染的页面中时,无法写入_Layout.cshtml。

自定义HtmlHelper扩展代码如下:

public static class HtmlHelperExtensions
{
    private static IHttpContextAccessor httpContextAccessor;
    public static HtmlString AddResource(this IHtmlHelper htmlHelper, PageResourceType resourceType, string identifier, Func<object, HelperResult> template)
    {
        httpContextAccessor = Service.Resolve<IHttpContextAccessor>();
        if (httpContextAccessor.HttpContext.Items[resourceType] != null)
        {
            ((List<(Func<object, HelperResult>, string)>)httpContextAccessor.HttpContext.Items[resourceType]).Add((template, identifier));
        }
        else
        {
            httpContextAccessor.HttpContext.Items[resourceType] = new List<(Func<object, HelperResult>, string)>() { (template, identifier) };
        }

        return new HtmlString(string.Empty);
    }

    public static HtmlString RenderResources(this IHtmlHelper htmlHelper, PageResourceType resourceType)
    {
        httpContextAccessor = Service.Resolve<IHttpContextAccessor>();
        if (httpContextAccessor.HttpContext.Items[resourceType] != null)
        {
            List<(Func<object, HelperResult>, string)> resources = (List<(Func<object, HelperResult>, string)>)httpContextAccessor.HttpContext.Items[resourceType];

            foreach (var resource in resources.DistinctBy(r => r.Item2))
            {
                if (resource.Item1 != null)
                {
                    htmlHelper.ViewContext.Writer.Write(resource.Item1(null));
                }
            }
        }

        return new HtmlString(string.Empty);
    }
}

_Layout.cshtml中的调用方式:

@Html.RenderResources(PageResourceType.HeadScript)
问题原因
  1. 静态字段线程安全问题:扩展中使用了静态的httpContextAccessor,多请求并发场景下会导致上下文混乱,影响资源的正确存储与读取。
  2. 渲染时机不匹配:如果@Html.RenderResources在_Layout.cshtml的<head>标签中调用(早于@RenderBody()执行),PartialWidgetPage渲染时添加的资源会在RenderResources执行之后才存入HttpContext.Items,无法被渲染输出。
解决方案

1. 修复HtmlHelper扩展的线程安全问题

移除静态的httpContextAccessor,直接从当前IHtmlHelper的ViewContext获取请求上下文,避免并发冲突:

public static class HtmlHelperExtensions
{
    public static HtmlString AddResource(this IHtmlHelper htmlHelper, PageResourceType resourceType, string identifier, Func<object, HelperResult> template)
    {
        var httpContext = htmlHelper.ViewContext.HttpContext;
        if (httpContext.Items.TryGetValue(resourceType, out var existing))
        {
            if (existing is List<(Func<object, HelperResult>, string)> resources)
            {
                resources.Add((template, identifier));
            }
        }
        else
        {
            httpContext.Items[resourceType] = new List<(Func<object, HelperResult>, string)>() { (template, identifier) };
        }

        return new HtmlString(string.Empty);
    }

    public static HtmlString RenderResources(this IHtmlHelper htmlHelper, PageResourceType resourceType)
    {
        var httpContext = htmlHelper.ViewContext.HttpContext;
        if (httpContext.Items.TryGetValue(resourceType, out var existing))
        {
            if (existing is List<(Func<object, HelperResult>, string)> resources)
            {
                foreach (var resource in resources.DistinctBy(r => r.Item2))
                {
                    resource.Item1?.Invoke(null)?.WriteTo(htmlHelper.ViewContext.Writer);
                }
            }
        }

        return new HtmlString(string.Empty);
    }
}

2. 调整渲染顺序确保资源被收集

将@Html.RenderResources的调用位置移到@RenderBody()之后(比如</body>标签前),确保所有页面内容(包括PartialWidgetPage中的部件)渲染时添加的资源,能在RenderResources执行前被存入HttpContext.Items并输出:

<!-- _Layout.cshtml -->
<body>
    @RenderBody()
    
    <!-- 移到此处,确保所有内容渲染完成后再输出资源 -->
    @Html.RenderResources(PageResourceType.HeadScript)
</body>

如果必须将资源输出到<head>标签中,可考虑异步渲染或提前收集部件资源,但复杂度较高,优先推荐调整渲染顺序的方案。

内容的提问来源于stack exchange,提问作者rory

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 18:54:56