ASP.NET Core中如何在视图/分部视图中动态引入分部视图?
在ASP.NET Core中为视图及分部视图动态引入脚本分部视图
问题背景
使用webpack打包客户端资源,约定规则为:若同目录下存在与.cshtml视图同名的.ts文件,webpack会生成对应的{视图名}.scriptbundle.cshtml分部视图,内容为通过自定义RequireScript扩展方法引入编译后的JS文件:
@Html.RequireScript(@<script src='@Url.Content("~/dist/js/Index.js")' asp-append-version="true"></script>)
当前实现是通过布局文件自动引入该分部视图,但仅支持整页渲染;分部视图因无布局文件,无法自动引入对应的脚本分部视图。需要将自动引入逻辑移至核心层,同时支持整页和分部视图场景。
此前在ASP.NET中通过继承WebViewPage并重写ExecutePageHierarchy实现,但ASP.NET Core的视图渲染机制已变更,原扩展点不再适用。尝试修改Razor代码生成逻辑,但在.NET 8中找不到ICompilationService等相关接口。
解决方案:自定义Razor页面基类
在ASP.NET Core中,可通过自定义RazorPage基类,重写异步执行逻辑来实现自动检测并渲染脚本分部视图:
1. 创建自定义Razor页面基类
using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.AspNetCore.Mvc.ViewEngines; using System.IO; public class ScriptBundleRazorPage<TModel> : RazorPage<TModel> { public override async Task ExecuteAsync() { // 跳过脚本分部视图自身的递归处理 if (ViewContext.View.Path.EndsWith(".scriptbundle.cshtml", StringComparison.OrdinalIgnoreCase)) { await base.ExecuteAsync(); return; } // 执行原视图渲染逻辑 await base.ExecuteAsync(); // 构造对应脚本分部视图的路径 var originalViewPath = ViewContext.View.Path; var scriptBundlePath = Path.ChangeExtension(originalViewPath, null) + ".scriptbundle.cshtml"; // 获取视图引擎并检查脚本分部视图是否存在 var viewEngine = HttpContext.RequestServices.GetRequiredService<ICompositeViewEngine>(); var viewResult = viewEngine.GetView(executingFilePath: null, viewPath: scriptBundlePath, isMainPage: false); if (viewResult.Success) { // 渲染脚本分部视图 await viewResult.View.RenderAsync(ViewContext); } } }
2. 全局配置视图基类
在Views/_ViewImports.cshtml中设置所有视图默认继承自定义基类:
@inherits ScriptBundleRazorPage<TModel>
若仅需针对特定视图/区域生效,可在对应视图的顶部单独添加@inherits指令。
3. 关键逻辑说明
- 递归规避:判断当前视图路径是否为脚本分部视图,避免无限递归渲染
- 路径构造:通过
Path.ChangeExtension移除原视图的.cshtml后缀,拼接脚本分部视图的命名后缀 - 视图存在性检查:使用
ICompositeViewEngine.GetView直接检查同目录下的脚本分部视图 - 共享上下文:渲染脚本分部视图时复用当前
ViewContext,确保RequireScript扩展方法能正常收集脚本并统一输出
替代方案:自定义视图引擎过滤器
若不想修改视图基类,可通过实现IViewEngine的装饰器,在视图查找完成后自动添加脚本分部视图的渲染逻辑,但实现复杂度更高,不如基类方式直观。
内容的提问来源于stack exchange,提问作者RikRak
相关产品推荐
相关产品推荐

