ASP.NET Core MVC中如何渲染存储在Model属性中的Cshtml内容
Html.Raw仅负责将字符串跳过HTML编码直接输出,不具备Razor语法解析、变量绑定能力,因此无法解析模板中的@Model.Property片段,你需要对存储的Razor模板做动态编译渲染,以下是两种可落地的实现方案:
方案1:基于ASP.NET Core内置组件实现动态Razor渲染
无需引入第三方依赖,通过IRazorViewEngine实现模板的动态编译与渲染:
- 第一步:封装动态渲染服务
public interface IRazorTemplateRenderer { Task<string> RenderToStringAsync(string templateContent, object model); } public class RazorTemplateRenderer : IRazorTemplateRenderer { private readonly IRazorViewEngine _razorViewEngine; private readonly ITempDataProvider _tempDataProvider; private readonly IHttpContextAccessor _httpContextAccessor; public RazorTemplateRenderer(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IHttpContextAccessor httpContextAccessor) { _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _httpContextAccessor = httpContextAccessor; } public async Task<string> RenderToStringAsync(string templateContent, object model) { var httpContext = _httpContextAccessor.HttpContext ?? new DefaultHttpContext { RequestServices = BuildServiceProvider() }; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); using var sw = new StringWriter(); var dynamicPage = new DynamicRazorPage($"DynamicTemplate_{Guid.NewGuid()}", templateContent); var view = new RazorView(_razorViewEngine, Enumerable.Empty<IRazorPageFactoryProvider>(), Enumerable.Empty<IRazorPageActivator>(), new HtmlHelperOptions(), new RazorViewOptions(), dynamicPage, Enumerable.Empty<IControllerPropertyActivator>()); var viewContext = new ViewContext( actionContext, view, new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) { Model = model }, new TempDataDictionary(actionContext.HttpContext, _tempDataProvider), sw, new HtmlHelperOptions() ); await view.RenderAsync(viewContext); return sw.ToString(); } private IServiceProvider BuildServiceProvider() { var services = new ServiceCollection(); services.AddSingleton(_razorViewEngine); services.AddSingleton(_tempDataProvider); return services.BuildServiceProvider(); } } // 自定义动态Razor页加载模板内容 public class DynamicRazorPage : IRazorPage { private readonly string _templateContent; public DynamicRazorPage(string path, string templateContent) { Path = path; _templateContent = templateContent; } public async Task ExecuteAsync() => await Output.WriteAsync(_templateContent); public string Path { get; } public ViewContext ViewContext { get; set; } public TextWriter Output { get; set; } public bool IsLayoutBeingRendered { get; set; } public string Layout { get; set; } public IDictionary<string, RenderAsyncDelegate> PreviousSectionWriters { get; set; } public IDictionary<string, RenderAsyncDelegate> SectionWriters { get; } = new Dictionary<string, RenderAsyncDelegate>(); }
- 第二步:注册服务,在
Program.cs中添加如下配置:
builder.Services.AddHttpContextAccessor(); builder.Services.AddScoped<IRazorTemplateRenderer, RazorTemplateRenderer>();
- 第三步:控制器中调用渲染逻辑
public async Task<IActionResult> Index() { // 从数据库读取存储的cshtml模板 var dbTemplate = await _yourDbContext.PageTemplates.FindAsync(templateId); // 构造需要绑定的业务Model var pageModel = new YourPageModel { Property = "需要插入的属性值" }; // 渲染得到最终HTML var finalHtml = await _razorTemplateRenderer.RenderToStringAsync(dbTemplate.Content, pageModel); // 传递到视图 ViewBag.FinalHtml = finalHtml; return View(pageModel); }
- 第四步:视图中直接输出渲染结果
@Html.Raw(ViewBag.FinalHtml)
方案2:轻量场景下的字符串替换方案
如果存储的模板只有简单的@Model.xxx变量引用,没有循环、判断、嵌套调用等复杂Razor语法,可以用反射实现变量批量替换,性能远高于动态编译:
public string ReplaceTemplateVariables(string template, object model) { var properties = model.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in properties) { var value = prop.GetValue(model)?.ToString() ?? string.Empty; template = template.Replace($"@Model.{prop.Name}", value); } return template; }
替换后的字符串直接用@Html.Raw输出即可。
注意事项
- 动态编译模板存在一定性能开销,建议对不变的模板加缓存,避免每次请求重复编译
- 若存储的模板支持用户自定义编辑,需做好安全校验,避免恶意代码注入风险
内容的提问来源于stack exchange,提问作者Peej
相关产品推荐
相关产品推荐

