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

Razor Pages:如何向布局页/部分视图传递数据库数据及配置PageModel

问题原因

错误的核心是布局页会继承内容页的模型:你给布局页指定了LayoutModel,但内容页(比如Index页)传递的是自身的IndexModel,类型不匹配导致抛出异常。


解决方案

方案1:用ViewData/ViewBag传递数据(快速简单)

不需要修改布局页模型,直接在内容页加载数据存入ViewData,布局页读取使用:

  1. 在每个内容页的PageModel中加载数据:
public class IndexModel : PageModel
{
    private readonly ApplicationDbContext _db;

    public IndexModel(ApplicationDbContext db)
    {
        _db = db;
    }

    public async Task OnGetAsync()
    {
        // 将项目数据存入ViewData
        ViewData["UserProjects"] = await _db.UserProject.ToListAsync();
    }
}
  1. 修改布局页的下拉菜单代码:
<li class="nav-item dropdown">
    <a class="nav-link dropdown-toggle" href="#" id="navbardrop" data-toggle="dropdown">
        Projects
    </a>
    <div class="dropdown-menu">
        @foreach(var p in (List<UserProject>)ViewData["UserProjects"])
        {
            <a class="dropdown-item text-dark" asp-area="" asp-page="/Category Display/Index" asp-route-projectId="@p.Id">@p.productName</a>
        }
    </div>
</li>

缺点:每个内容页都要重复编写加载数据的代码,适合小型项目。


方案2:使用ViewComponent(推荐)

ViewComponent是Razor Pages官方推荐的、用于复用带逻辑视图片段的组件,完美解决布局页/部分视图需要独立数据逻辑的场景——它自带专属的逻辑处理类,就是你想要的「类似PageModel的结构」。

步骤1:创建ViewComponent类

在项目根目录新建Components文件夹,添加ProjectsDropdownViewComponent.cs:

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

public class ProjectsDropdownViewComponent : ViewComponent
{
    private readonly ApplicationDbContext _db;

    public ProjectsDropdownViewComponent(ApplicationDbContext db)
    {
        _db = db;
    }

    // InvokeAsync相当于组件的"OnGet"方法,处理数据逻辑
    public async Task<IViewComponentResult> InvokeAsync()
    {
        var userProjects = await _db.UserProject.ToListAsync();
        return View(userProjects); // 向视图传递数据
    }
}

步骤2:创建组件对应的视图

在Pages/Shared/Components/ProjectsDropdown目录下新建Default.cshtml(目录名需和组件类名去掉ViewComponent后缀一致):

@model List<UserProject>

<li class="nav-item dropdown">
    <a class="nav-link dropdown-toggle" href="#" id="navbardrop" data-toggle="dropdown">
        Projects
    </a>
    <div class="dropdown-menu">
        @foreach(var p in Model)
        {
            <a class="dropdown-item text-dark" asp-area="" asp-page="/Category Display/Index" asp-route-projectId="@p.Id">@p.productName</a>
        }
    </div>
</li>

步骤3:在布局页引用组件

替换布局页中原有的下拉菜单代码,直接调用组件:

@await Component.InvokeAsync("ProjectsDropdown")

优点:逻辑与视图完全复用,无需在每个内容页重复编写代码,扩展性强。


方案3:基础PageModel继承(不推荐)

让所有内容页的PageModel继承一个包含项目数据的基础模型,但灵活性差:

  1. 创建基础PageModel:
public class BasePageModel : PageModel
{
    private readonly ApplicationDbContext _db;

    public List<UserProject> UserProjects { get; set; }

    public BasePageModel(ApplicationDbContext db)
    {
        _db = db;
    }

    public async Task OnGetBaseAsync()
    {
        UserProjects = await _db.UserProject.ToListAsync();
    }
}
  1. 内容页继承基础模型并调用基础方法:
public class IndexModel : BasePageModel
{
    public IndexModel(ApplicationDbContext db) : base(db)
    {
    }

    public async Task OnGetAsync()
    {
        await OnGetBaseAsync();
    }
}
  1. 布局页指定模型为BasePageModel:
@model BasePageModel

<li class="nav-item dropdown">
    <a class="nav-link dropdown-toggle" href="#" id="navbardrop" data-toggle="dropdown">
        Projects
    </a>
    <div class="dropdown-menu">
        @foreach(var p in Model.UserProjects)
        {
            <a class="dropdown-item text-dark" asp-area="" asp-page="/Category Display/Index" asp-route-projectId="@p.Id">@p.productName</a>
        }
    </div>
</li>

缺点:所有内容页必须强制继承基础模型,新增页面时容易遗漏,扩展性差。


关于部分视图的"PageModel"结构

可以通过ViewComponent实现,它自带独立的依赖注入(比如注入DbContext)和逻辑处理方法(InvokeAsync),相当于给部分视图绑定了专属的逻辑类,完全满足你需要的「类似PageModel的结构」,这也是Razor Pages中最规范的实现方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 16:05:27