在 ASP.NET 中,实现这种布局有几种主流方式,我会从最经典、最强大的方式讲起,再到更现代、更灵活的方式。

核心思想:避免重复代码
网页框架的核心目标是“Don't Repeat Yourself” (DRY),我们不希望在每个页面都写一遍 <header>, <footer>, <nav> 的 HTML 代码,ASP.NET 提供了多种机制来解决这个问题,让我们可以创建一个可复用的“模板”。
ASP.NET Web Forms (经典方式)
这是 ASP.NET 最早也是最成熟的模式,它通过 母版页 来实现框架。
母版页
母版页是一个扩展名为 .master 的特殊文件,它定义了整个网站的“骨架”和“皮肤”,它包含静态的 HTML 元素(如页头、页脚)和可替换的内容占位符。
创建步骤:

- 在 Visual Studio 中,右键项目 -> 添加 -> 新建项 -> 选择“母版页”,命名为
Site.master。 - 你会看到一个类似普通页面的结构,但有一个特殊的
<asp:ContentPlaceHolder>控件。
Site.master 示例代码:
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="MyWebApp.SiteMaster" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head runat="server">
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><%: Page.Title %> - 我的 ASP.NET 应用</title>
<asp:PlaceHolder runat="server">
<%: Scripts.Render("~/bundles/modernizr") %>
</asp:PlaceHolder>
<webopt:bundlereference runat="server" path="~/Content/css" />
<link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
</head>
<body>
<form runat="server">
<asp:ScriptManager runat="server">
<Scripts>
<%--To learn more about bundling and minification please visit https://go.microsoft.com/fwlink/?LinkId=301862 --%>
<%--Framework Scripts--%>
<asp:ScriptReference Name="MsAjaxBundle" />
<asp:ScriptReference Name="jquery" />
<asp:ScriptReference Name="bootstrap" />
<asp:ScriptReference Name="respond" />
<asp:ScriptReference Name="WebForms.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebForms.js" />
<asp:ScriptReference Name="WebUIValidation.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebUIValidation.js" />
<asp:ScriptReference Name="MenuStandards.js" Assembly="System.Web" Path="~/Scripts/WebForms/MenuStandards.js" />
<asp:ScriptReference Name="GridView.js" Assembly="System.Web" Path="~/Scripts/WebForms/GridView.js" />
<asp:ScriptReference Name="DetailsView.js" Assembly="System.Web" Path="~/Scripts/WebForms/DetailsView.js" />
<asp:ScriptReference Name="TreeView.js" Assembly="System.Web" Path="~/Scripts/WebForms/TreeView.js" />
<asp:ScriptReference Name="WebParts.js" Assembly="System.Web" Path="~/Scripts/WebForms/WebParts.js" />
<asp:ScriptReference Name="Focus.js" Assembly="System.Web" Path="~/Scripts/WebForms/Focus.js" />
<asp:ScriptReference Name="WebFormsBundle" />
<%--Site Scripts--%>
</Scripts>
</asp:ScriptManager>
<!-- 这是页头部分,所有页面共享 -->
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" runat="server" href="~/">应用名称</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a runat="server" href="~/">首页</a></li>
<li><a runat="server" href="~/About.aspx">lt;/a></li>
<li><a runat="server" href="~/Contact.aspx">联系我们</a></li>
</ul>
</div>
</div>
</nav>
<div class="container body-content">
<!--
这是内容占位符!
在使用此母版页的页面中,只有这里的部分可以被替换。
-->
<asp:ContentPlaceHolder ID="MainContent" runat="server">
</asp:ContentPlaceHolder>
</div>
<!-- 这是页脚部分,所有页面共享 -->
<footer>
<div class="container">
<p>© <%: DateTime.Now.Year %> - 我的 ASP.NET 应用</p>
</div>
</footer>
</form>
</body>
</html>
内容页
页是一个普通的 .aspx 文件,它被“绑定”到一个母版页,内容页不包含 <html>, <head>, <body> 等标签,只包含 <asp:Content> 控件,这些控件会填充母版页中对应的 <asp:ContentPlaceHolder>。
创建步骤:
- 右键项目 -> 添加 -> 新建项 -> 选择“Web 窗体”。
- 在弹出的对话框中,勾选“选择母版页”选项,然后选择你刚才创建的
Site.master。 - 点击“添加”。
About.aspx 示例代码:

<%@ Page Title="quot; Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="About.aspx.cs" Inherits="MyWebApp.About" %>
<!--
Content 控件的 ContentPlaceHolderID 必须与母版页中 PlaceHolder 的 ID 完全匹配。
这里的 "MainContent" 就对应 Site.master 中的 <asp:ContentPlaceHolder ID="MainContent" runat="server">。
-->
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
<h2><%: Title %></h2>
<h3>关于我们</h3>
<p>将此内容替换为关于我们页面的说明。</p>
</asp:Content>
优点:
- 强类型绑定:编译时检查,ContentPlaceHolderID 不匹配会报错。
- 设计器支持好:在设计视图中可以清晰地看到母版页和内容页的结构。
- 功能强大:可以方便地在母版页中访问内容页的属性和方法(反之亦然)。
缺点:
- 耦合度高页和母版页紧密绑定,更换母版页比较麻烦。
- 文件结构复杂页都有一个对应的
.cs代码文件和一个.master文件,文件数量较多。
ASP.NET MVC (现代方式)
ASP.NET MVC 采用的是布局页 的概念,与母版页类似,但语法更简洁,与视图引擎(如 Razor)结合更紧密。
布局页
布局页也是一个模板,通常位于 Views/Shared/_Layout.cshtml,它使用 Razor 语法来定义可替换的区域。
Views/Shared/_Layout.cshtml 示例代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />@ViewData["Title"] - MyASP.NETCoreApp</title>
<environment include="Development">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</environment>
<environment exclude="Development">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css"
asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
<link rel="stylesheet" href="~/css/site.min.css"
asp-fallback-href="~/css/site.css"
asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
</environment>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">应用名称</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a asp-area="" asp-controller="Home" asp-action="Index">首页</a></li>
<li><a asp-area="" asp-controller="Home" asp-action="About">lt;/a></li>
<li><a asp-area="" asp-controller="Home" asp-action="Contact">联系我们</a></li>
</ul>
</div>
</div>
</nav>
<div class="container body-content">
<!--
@RenderBody() 是必须的,它表示将具体视图的内容“渲染”到这里。
-->
@RenderBody()
<hr />
<footer>
<p>© @DateTime.Now.Year - My ASP.NET Core 应用</p>
</footer>
</div>
<environment include="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
</environment>
<environment exclude="Development">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js"
asp-fallback-test="window.jQuery"
crossorigin="anonymous"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMxqIChqDr36Lur+ke4Q=">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"
asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js"
asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal"
crossorigin="anonymous"
integrity="sha256-dq1wzW5W4fEI05OQ7SnpJsk8eiiEe2QoUy5k8/+GpUo=">
</script>
<script src="~/js/site.min.js" asp-append-version="true"></script>
</environment>
<!--
可选:用于在特定页面中渲染额外的脚本或样式。
一个表单验证页面可以在这里引入自己的 JS 文件。
-->
@RenderSection("Scripts", required: false)
</body>
</html>
视图
视图文件(如 About.cshtml)通过 Layout 属性指定使用哪个布局页。
Views/Home/About.cshtml 示例代码:
@{
ViewData["Title"] = "quot;;
}
<h2>@ViewData["Title"]</h2>
<h3>关于我们</h3>
替换为关于我们页面的说明。</p>
@section Scripts {
<!--
这里定义的 Scripts 会被渲染到 _Layout.cshtml 中 @RenderSection("Scripts") 的位置。
这是添加页面特定脚本和样式的标准方式。
-->
<script>
alert("这是关于页面的特定脚本!");
</script>
}
优点:
- 语法简洁:Razor 语法非常清晰易读。
- 灵活性高:
@RenderSection提供了比 Web Forms 母版页更灵活的扩展点。 - 关注点分离:MVC 模式天然地将控制器、模型和视图分离,结构更清晰。
- 现代 Web 开发标准:与前端技术栈(如 Webpack, Vite)结合更容易。
缺点:
- 学习曲线:对于初学者,MVC 的概念(控制器、路由、模型绑定)比 Web Forms 更复杂。
ASP.NET Core Blazor (新兴方式)
Blazor 是一个用于使用 .NET 构建交互式客户端 Web UI 的框架,它完全颠覆了传统的请求-响应模式,采用组件化的方式来构建整个应用,包括页面框架。
在 Blazor 中,整个应用(包括布局)都是由一个个可复用的组件组成的。
布局组件
布局组件本质上也是一个 Blazor 组件,但它通常包含一个 @Body 占位符。
Shared/MainLayout.razor 示例代码:
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<!--
@Body 会在这里渲染当前页面的内容。
这与 MVC 的 @RenderBody 和 Web Forms 的 ContentPlaceHolder 类似。
-->
@Body
</main>
</div>
页面组件
页面组件(如 About.razor)通过 @layout 指令指定其布局。
Pages/About.razor 示例代码:
@page "/about" @layout MainLayout <h3>lt;/h3> <p>这是一个使用 Blazor 组件化方式构建的关于页面。</p>
优点:
- 全栈 .NET:前端和后端都可以用 C# 编写,共享代码库。
- 组件化:UI 被拆分成高度可复用、可维护的组件,构建大型应用非常强大。
- 现代交互:无需 JavaScript,即可构建复杂的客户端交互。
缺点:
- 较新技术:生态系统和社区资源相对 MVC 和 Web Forms 较少。
- 性能考量:对于大型应用,客户端 Blazor 的初始加载包大小可能是一个需要优化的点。
总结与选择
| 特性 | ASP.NET Web Forms (母版页) | ASP.NET MVC (布局页) | ASP.NET Core Blazor (布局组件) |
|---|---|---|---|
| 核心概念 | 母版页 和 内容页 | 布局页 (_Layout.cshtml) 和 视图 |
布局组件 和 页面组件 |
| 语法 | ASPX/Web Controls | Razor | Razor |
| 耦合度 | 较高 | 中等 | 低 (纯组件化) |
| 开发模式 | 事件驱动,类似 WinForms | MVC (模型-视图-控制器) | 组件化,类似 React/Vue |
| 适用场景 | 维护旧项目,或需要快速开发企业级内部系统 | 目前最主流的选择,适合大多数新 Web 应用 | 构建交互性强的现代单页应用,全栈 .NET 团队 |
| 推荐度 | 不推荐用于新项目 | 强烈推荐 | 适合特定场景,非常有前景 |
如何选择?
-
如果你要开始一个全新的项目:
- 首选 ASP.NET MVC,它是目前最成熟、社区最活跃、资源最丰富的选择,适合构建绝大多数类型的网站。
- 如果你的团队是全栈 .NET 开发者,并且希望构建一个交互性非常强的客户端应用(类似桌面应用的体验),Blazor 是一个值得尝试的未来方向。
-
如果你需要维护一个旧的 ASP.NET Web Forms 项目:
继续使用和优化现有的母版页结构是合理的,如果条件允许,可以考虑逐步将其迁移到 MVC 以获得更好的长期维护性。
希望这个详细的解释能帮助你理解 ASP.NET 中实现网页框架的各种方法!
