我们将遵循现代 Web 开发的最佳实践,主要介绍 ASP.NET Core 中的布局方式,因为它是目前的主流和未来方向,我也会简要提及传统的 ASP.NET Web Forms 的布局方式作为对比。

目录
- 为什么需要布局?
- 核心概念: Razor Pages, Views, 和 Layouts
- 实战教程:创建你的第一个布局
- 步骤 1:创建 Layout 文件
- 步骤 2:定义内容占位符
@RenderBody() - 步骤 3:创建一个 View 并应用布局
- 步骤 4:运行并查看效果
- 进阶布局技巧
- Section(节):实现布局中的可变部分(如页脚脚本、侧边栏)
- Partial Views(局部视图):复用 UI 组件(如导航栏、卡片)
- Tag Helpers:简化 HTML 标签的编写
- 组件化与 Blazor:未来的 UI 构建方式
- 传统 ASP.NET Web Forms 布局(Master Pages)
- 最佳实践与总结
为什么需要布局?
想象一下,如果你的网站有 100 个页面,每个页面都包含相同的头部(Logo、导航菜单)和底部(版权信息、联系方式),当你需要修改导航菜单时,难道要打开并修改 100 个文件吗?
布局 正是为了解决这个问题而生,它定义了一个网站的“外壳”或“模板”,所有页面内容都填充在这个外壳中,这样做的好处显而易见:
- 代码复用:将公共部分(Header, Footer, Navigation)提取到布局文件中,避免重复编写。
- 易于维护:只需修改布局文件,即可更新整个网站的外观和结构。
- 一致性:确保所有页面拥有统一的结构和风格。
核心概念:Razor Pages, Views, 和 Layouts
在 ASP.NET Core MVC 和 Razor Pages 模型中,布局的实现依赖于三个核心概念:
- Layout (布局文件):一个包含 HTML 结构的模板文件,通常位于
/Views/Shared/_Layout.cshtml或/Pages/Shared/_Layout.cshtml,文件名_开头是一种约定,表示它是一个“部分”或“辅助”文件,不应被直接请求。 - View (视图):显示特定数据的 HTML 模板,一个关于页面的视图文件可能是
/Views/Home/About.cshtml。 @RenderBody():这是布局文件中最重要的一个指令,它是一个占位符,当用户请求一个页面时,ASP.NET Core 会将对应视图的 HTML 内容“渲染”并插入到@RenderBody()所在的位置。
工作流程图解:

[用户请求 /Home/About]
|
V
[控制器找到 About.cshtml 视图]
|
V
[系统查找 _Layout.cshtml 布局]
|
V
[将 About.cshtml 的内容填充到 @RenderBody() 的位置]
|
V
[生成最终的完整 HTML 页面,返回给用户]
实战教程:创建你的第一个布局
我们将使用 Visual Studio 和 ASP.NET Core Razor Pages 项目模板来完成这个教程。
步骤 1:创建 Layout 文件
- 在 Visual Studio 中创建一个新的 ASP.NET Core Web 应用程序。
- 选择 “ASP.NET Core Web App” 模板,确保选择的是 Razor Pages。
- 在解决方案资源管理器中,右键点击
Pages文件夹 ->添加->新建文件夹,命名为Shared。 - 右键点击刚刚创建的
Shared文件夹 ->添加->新建项。 - 选择 “Razor Layout”,命名为
_Layout.cshtml,然后点击“添加”。
步骤 2:定义内容占位符 @RenderBody()
打开 _Layout.cshtml 文件,你会看到一个基础的 HTML5 模板,在 <body> 标签内,找到 @RenderBody() 指令,这就是我们内容将要插入的地方。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />@ViewData["Title"] - MyWebApp</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-dark bg-dark border-bottom box-shadow mb-3">
<div class="container-fluid">
<a class="navbar-brand" asp-area="" asp-page="/Index">MyWebApp</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-light" asp-area="" asp-page="/Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-light" asp-area="" asp-page="/Privacy">Privacy</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
<!--
这是核心!所有页面的内容都会被渲染到这里。
比如你访问 /Privacy.cshtml,Privacy.cshtml 的内容就会出现在这里。
-->
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2025 - MyWebApp
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
<!-- 在 RenderBody 之后渲染的脚本 -->
@RenderSection("Scripts", required: false)
</body>
</html>
关键点:
@ViewData["Title"]:我们可以在每个页面中设置ViewData["Title"]的值,来动态改变页面标题。@RenderBody()的核心插入点。@RenderSection("Scripts", required: false):这是一个可选的节,用于在布局的底部插入特定页面所需的脚本。required: false表示不是所有页面都需要提供这个节。
步骤 3:创建一个 View 并应用布局
默认情况下,新项目会自动为你创建 Index.cshtml 和 Privacy.cshtml,并且它们已经配置好了使用 _Layout.cshtml,我们来看看 Privacy.cshtml 是如何配置的。

打开 Pages/Privacy.cshtml:
@page
@model PrivacyModel
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
@page:指令,表明这是一个 Razor Page,可以直接通过 URL 访问。@model PrivacyModel:指定此页面使用的 C# 模型。- 代码块,我们在这里设置了
ViewData["Title"]。
注意:你不需要在 View 中显式指定使用哪个 Layout,ASP.NET Core 会按照约定自动查找 /Pages/Shared/_Layout.cshtml 或 /Views/Shared/_Layout.cshtml,如果你想使用不同的布局,可以在 View 的代码块中设置 Layout = "_AnotherLayout";。
步骤 4:运行并查看效果
按 F5 运行你的应用程序。
- 访问首页 (),你会看到
_Layout.cshtml中的所有元素(Header, Footer),@RenderBody()的位置被替换成了Index.cshtml的内容。 - 访问隐私页 (
/Privacy),你会看到 Header 和 Footer 保持不变,但@RenderBody()的内容变成了Privacy.cshtml的内容,并且页面标题也变成了 "Privacy Policy"。
进阶布局技巧
Section(节)
假设你希望在某个特定页面(比如一个包含复杂图表的页面)的底部加载一个额外的 JavaScript 文件,但你不想在每个页面都加载它,这时就可以使用 Section。
-
在
_Layout.cshtml中定义一个节: 我们已经看到了@RenderSection("Scripts", required: false),这定义了一个名为 "Scripts" 的节,并且它是可选的。 -
在 View 中为这个节提供内容: 修改
Privacy.cshtml,在文件末尾添加以下代码:@* ... 其他代码 ... *@ @section Scripts { <script> console.log("This is a script specific to the Privacy page!"); </script> } -
运行效果: 当你访问
/Privacy时,这个<script>标签会被插入到_Layout.cshtml中@RenderSection("Scripts")的位置,而当你访问首页时,这个脚本不会被加载。
Partial Views(局部视图)
局部视图是可重用的 UI 片段,你的网站可能在多个地方都需要显示一个“热门文章列表”。
-
创建局部视图: 在
Shared文件夹下,添加一个新项,选择 “Razor View”,命名为_ArticleList.cshtml。 在这个文件中,编写你的列表 HTML 代码:@* _ArticleList.cshtml *@ <h3>热门文章</h3> <ul> <li><a href="#">如何学习 ASP.NET Core</a></li> <li><a href="#">Razor 语法详解</a></li> <li><a href="#">Entity Core 使用指南</a></li> </ul> -
在布局或其他视图中使用局部视图: 使用
@await Html.PartialAsync("_ArticleList")或@await Component.InvokeAsync(...)来渲染它。在
_Layout.cshtml的<main>标签内添加:<main role="main" class="pb-3"> <div class="row"> <div class="col-md-9"> @RenderBody() </div> <div class="col-md-3"> <h2>侧边栏</h2> @* 调用局部视图 *@ @await Html.PartialAsync("_ArticleList") </div> </div> </main>
你的布局就多了一个显示热门文章的侧边栏。
Tag Helpers
Tag Helpers 是一种让服务器端代码参与生成 HTML 的语法,它让 HTML 更加清晰和易于阅读。
<a asp-page="/About">:比<a href="/About">更好,因为它会自动处理 URL 路径,即使你以后更改了路由配置,它也能正常工作。<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />:asp-append-version="true"会在 URL 后面添加一个查询字符串,如?v=xxxxxxxx,这对于缓存非常有益,当文件内容改变时,这个版本号也会改变,从而强制浏览器重新下载文件。
传统 ASP.NET Web Forms 布局(Master Pages)
如果你还在维护旧的 ASP.NET Web Forms 项目,布局是通过 Master Pages 实现的,其概念与 Layouts 非常相似。
- Master Page 文件:扩展名是
.master(Site.master),它和_Layout.cshtml结构一样,也包含一个内容占位符。 - 内容占位符:Web Forms 中使用
<asp:ContentPlaceHolder>标签。<!-- Site.master --> <body> <form id="form1" runat="server"> <div> <asp:ContentPlaceHolder ID="MainContent" runat="server"> </asp:ContentPlaceHolder> </div> </form> </body> - Content Page (内容页):扩展名是
.aspx,它通过<asp:Content>标签来提供内容,并通过ContentPlaceID属性指定要填充到哪个占位符。<!-- About.aspx --> <asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server"> <h2>关于我们</h2> <p>这里是关于我们的内容。</p> </asp:Content>
虽然语法不同,但核心思想是完全一样的:模板 + 内容占位符。
最佳实践与总结
- 遵循约定:将布局文件放在
/Views/Shared/或/Pages/Shared/目录下,并命名为_Layout.cshtml,这是 ASP.NET Core 的默认约定,能简化配置。 - 保持布局简洁:布局文件应该只包含网站的公共结构(Header, Footer, Navigation),不要在布局中放置复杂的业务逻辑。
- 合理使用 Sections:将页面特定的脚本、样式或 HTML 块放在 Sections 中,以保持布局的通用性。
- 拥抱组件化:对于可重用的 UI 片段(如导航栏、卡片、用户信息框),优先使用 Partial Views 或 View Components,而不是在多个地方复制粘贴代码。
- 从 Layout 开始:在开发任何新页面之前,先设计并实现好你的
_Layout.cshtml,这能确保整个网站的一致性。 - 展望未来:对于全新的项目,可以关注 Blazor,Blazor 是一个使用 C# 而不是 JavaScript 来构建交互式 Web UI 的框架,它有自己的组件模型,你可以在一个
.razor文件中创建可复用的 UI 组件,这代表了 Web UI 开发的未来方向,其组件化思想比传统的布局更进一步。
希望这份详细的教程能帮助你掌握 ASP.NET 网站布局!从基础布局到高级技巧,逐步实践,你很快就能构建出结构清晰、易于维护的专业网站。
