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

.NET 6.0中如何非动态添加Razor视图/.chtml文件

.NET 6 MVC 动态生成小说详情视图的解决方案

针对你需要基于数据库Novel对象自动生成视图、且兼容后续评论/浏览量统计功能的需求,下面提供.NET 6环境下的可行方案,替代旧版MVC 4的字符串视图方案:

核心思路

放弃生成物理视图文件的方式,改用Razor运行时编译动态渲染字符串模板。这种方式不需要手动创建或编辑视图文件,直接通过代码将Novel对象的属性注入模板生成HTML,同时天然支持后续扩展评论、浏览量统计等动态功能。

具体实现步骤

1. 安装必要NuGet包

在项目中安装运行时编译依赖:

Install-Package Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation

2. 配置Program.cs启用运行时编译

在服务注册中添加运行时编译支持:

var builder = WebApplication.CreateBuilder(args);

// 添加MVC服务并启用Razor运行时编译
builder.Services.AddControllersWithViews()
    .AddRazorRuntimeCompilation();

var app = builder.Build();

// 常规中间件配置
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

3. 封装动态视图渲染服务

创建一个服务类,负责将字符串模板和模型编译为HTML:

using Microsoft.AspNetCore.Mvc.Razor;
using System.IO;
using System.Text.Encodings.Web;

public class DynamicViewRenderer
{
    private readonly IRazorViewEngine _razorViewEngine;
    private readonly ITempDataProvider _tempDataProvider;
    private readonly IServiceProvider _serviceProvider;

    public DynamicViewRenderer(IRazorViewEngine razorViewEngine,
                               ITempDataProvider tempDataProvider,
                               IServiceProvider serviceProvider)
    {
        _razorViewEngine = razorViewEngine;
        _tempDataProvider = tempDataProvider;
        _serviceProvider = serviceProvider;
    }

    // 将字符串模板和模型渲染为HTML字符串
    public async Task<string> RenderViewToStringAsync(string template, object model)
    {
        var actionContext = new ActionContext(
            new DefaultHttpContext { RequestServices = _serviceProvider },
            new RouteData(),
            new ControllerActionDescriptor());

        using var sw = new StringWriter();
        
        // 自定义Razor页面实例,用于编译字符串模板
        var razorTemplate = new RazorTemplate(template);
        var razorView = new RazorView(
            _razorViewEngine,
            NullViewComponentInvoker.Instance,
            new List<IRazorPage> { razorTemplate },
            razorTemplate,
            HtmlEncoder.Default);

        var viewContext = new ViewContext(
            actionContext,
            razorView,
            new ViewDataDictionary(
                new EmptyModelMetadataProvider(), 
                new ModelStateDictionary())
            { Model = model },
            new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
            sw,
            new HtmlHelperOptions());

        await razorView.RenderAsync(viewContext);
        return sw.ToString();
    }

    // 内部类:实现IRazorPage以编译字符串模板
    private class RazorTemplate : IRazorPage
    {
        private readonly string _templateContent;

        public RazorTemplate(string template) => _templateContent = template;

        public string Layout { get; set; }
        public string Path { get; set; } = "/Dynamic/Template.cshtml";
        public ViewContext ViewContext { get; set; }
        public IRazorPage ParentPage { get; set; }
        public bool IsLayoutBeingRendered { get; set; }
        public IViewComponentHelper ViewComponentHelper { get; set; }
        public IUrlHelper Url { get; set; }
        public dynamic ViewBag { get; set; }
        public PageContext PageContext { get; set; }

        public async Task ExecuteAsync()
        {
            await ViewContext.Writer.WriteAsync(_templateContent);
        }
    }
}

4. 注册渲染服务

在Program.cs中注册这个服务:

builder.Services.AddScoped<DynamicViewRenderer>();

5. 控制器中实现视图生成逻辑

假设你的Novel实体类如下:

public class Novel
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public string Author { get; set; }
    public int ChapterCount { get; set; }
    public decimal Rating { get; set; }
    public string Genre { get; set; }
    public string Tags { get; set; }
    // 后续扩展字段
    public int ViewCount { get; set; }
    public ICollection<Comment> Comments { get; set; } = new List<Comment>();
}

// 评论实体(后续扩展用)
public class Comment
{
    public int Id { get; set; }
    public string Content { get; set; }
    public int NovelId { get; set; }
    public Novel Novel { get; set; }
}

在控制器中编写方法,处理小说详情的视图渲染,同时集成浏览量统计:

public class NovelController : Controller
{
    private readonly AppDbContext _dbContext;
    private readonly DynamicViewRenderer _viewRenderer;

    public NovelController(AppDbContext dbContext, DynamicViewRenderer viewRenderer)
    {
        _dbContext = dbContext;
        _viewRenderer = viewRenderer;
    }

    public async Task<IActionResult> Detail(int id)
    {
        var novel = await _dbContext.Novels
            .Include(n => n.Comments) // 后续加载评论用
            .FirstOrDefaultAsync(n => n.Id == id);

        if (novel == null) return NotFound();

        // 更新浏览量统计
        novel.ViewCount++;
        await _dbContext.SaveChangesAsync();

        // 自定义Razor模板,替换模型属性
        var template = @"
@{
    Layout = ""_Layout""; // 复用项目的布局页
}

<div class=""novel-detail-container"">
    <h1>@Model.Title</h1>
    <div class=""meta-info"">
        <span>作者:@Model.Author</span>
        <span>流派:@Model.Genre</span>
        <span>标签:@Model.Tags</span>
        <span>评分:@Model.Rating</span>
        <span>章节数:@Model.ChapterCount</span>
        <span>浏览量:@Model.ViewCount</span>
    </div>
    <div class=""description"">@Model.Description</div>

    <!-- 评论区(后续扩展) -->
    <div class=""comments-section"">
        <h3>读者评论</h3>
        @foreach (var comment in Model.Comments)
        {
            <div class=""comment-item"">@comment.Content</div>
        }
        <!-- 评论提交表单可在此添加 -->
    </div>
</div>";

        // 渲染模板为HTML并返回
        var htmlContent = await _viewRenderer.RenderViewToStringAsync(template, novel);
        return Content(htmlContent, "text/html");
    }
}

方案优势与扩展建议

  • 灵活性高:不需要生成物理视图文件,修改模板只需调整字符串内容,无需批量更新文件;
  • 动态兼容:天然支持浏览量统计、评论列表等动态数据,后续扩展功能只需修改模板和实体类;
  • 性能优化:可将常用模板缓存,或对热门小说的渲染结果进行缓存,减少编译开销。

如果坚持要生成物理视图文件(不推荐,维护成本高),可通过文件IO读取模板文件、替换变量后写入新视图,但这种方式需要重启应用才能识别新视图,且后续模板修改需重新生成所有视图。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 08:15:37