ASP.NET Web Pages 中的「全局页面」完整指南
(适用于 Razor v2 / v3,也就是 WebMatrix 和 Visual Studio 里的 ASP.NET Web Pages)
在 ASP.NET Web Pages 中,没有 MVC 那种 Global.asax,但它提供了 5 种真正实用的“全局”机制,完全可以实现和 Global.asax 一样的效果:
| 全局功能 | 实现文件 | 触发时机 | 典型用途 |
|---|---|---|---|
| 全局启动代码 | _AppStart.cshtml | 应用程序第一次启动时执行一次 | 初始化数据库、缓存、路由注册、配置读取 |
| 全局每次请求前执行 | _PageStart.cshtml | 每个页面请求前执行(可分目录) | 权限检查、登录验证、通用 Layout 设置 |
| 全局布局(母版页) | _ViewStart.cshtml | 每个页面渲染前执行 | 统一指定 Layout |
| 全局异常处理 | _AppStart.cshtml + Web.config | 应用程序生命周期 | 记录错误日志、友好错误页 |
| 全局函数 / 助手 | App_Code 文件夹里的文件 | 随时可用 | @MyHelper.DateFormat()、公共工具类 |
下面详细讲解每一个,配完整代码。
1. _AppStart.cshtml —— 真正的「Global.asax」(只执行一次)
放在网站 根目录,文件名必须是 _AppStart.cshtml(下划线开头)。
@{
// 数据库初始化(经典用法)
var dbPath = "~/App_Data/MySite.sdf";
if (!File.Exists(Server.MapPath(dbPath))) {
Database.CreateDatabase("MySite.sdf"); // 自动创建 SQL CE 数据库
// 或者用 WebMatrix.Data
var db = Database.Open("MySite");
db.Execute(@"CREATE TABLE Users (
Id int IDENTITY(1,1) PRIMARY KEY,
UserName nvarchar(50),
Email nvarchar(100)
)");
db.Execute("INSERT INTO Users (UserName,Email) VALUES (@0,@1)", "admin", "admin@xxx.com");
}
// 自定义路由(可选,比默认路由更强大)
RouteTable.Routes.Add("ProductRoute", new Route(
url: "san-pham/{id}/{title}",
defaults: new RouteValueDictionary(new { page = "ProductDetail" })
));
// 全局缓存预热
var cacheKey = "SiteConfig";
if (Cache[cacheKey] == null) {
Cache[cacheKey] = new {
SiteName = "我的商城",
ICP = "京ICP备12345678号"
};
}
// 记录启动时间
Application["AppStartTime"] = DateTime.Now;
}
只要网站第一次被访问,这个文件就只运行一次,之后重启 IIS 或修改 Web.config 才会再次运行。
2. _PageStart.cshtml —— 每个请求都执行(支持分目录)
用途:权限控制、全站登录检查、统一注入数据等。
根目录的 _PageStart.cshtml(全站通用)
@{
// 所有页面都会先执行这里
var user = WebSecurity.CurrentUserName;
if (!user.IsEmpty() && user != "Guest") {
// 把登录用户信息注入所有页面
PageData["CurrentUser"] = Database.Open("MySite")
.QuerySingle("SELECT * FROM Users WHERE UserName=@0", user);
}
// 未登录且不是登录页 → 跳转登录
if (!WebSecurity.IsAuthenticated
&& Request.Url.AbsolutePath.ToLower() != "/Account/Login.cshtml") {
Response.Redirect("~/Account/Login.cshtml?ReturnUrl=" + Request.Url.PathAndQuery);
}
// 所有页面默认布局(也可以在这里动态决定)
Layout = "~/Shared/_Layout.cshtml";
}
Admin 文件夹下的 _PageStart.cshtml(只影响后台)
@{
// 先执行根目录的 _PageStart,再执行这里的(继承关系)
RunPageStart(); // 重要!不写这句根目录的就不执行了
// 管理员权限检查
if (!Roles.IsUserInRole("Admin")) {
Response.Redirect("~/Error/NoPermission.cshtml");
}
Layout = "~/Shared/_AdminLayout.cshtml";
}
3. _ViewStart.cshtml —— 只负责布局(你已经很熟了)
@{
// 通常只写这一行就够了
Layout = "~/Shared/_Layout.cshtml";
}
4. 全局异常处理(最实用的两种方式)
方式A:在 _AppStart.cshtml 里写
@{
WebPages.Application_Error += (sender, e) => {
var ex = Server.GetLastError();
// 记录日志
var logPath = Server.MapPath("~/App_Data/ErrorLog.txt");
File.AppendAllText(logPath,
DateTime.Now + " | " + ex.Message + "\r\n" + ex.StackTrace + "\r\n\r\n");
// 可选:发邮件给管理员
};
}
方式B:在 Web.config 里配友好错误页(推荐配合使用)
<system.web>
<customErrors mode="On" defaultRedirect="~/Error/ServerError.cshtml">
<error statusCode="404" redirect="~/Error/NotFound.cshtml"/>
</customErrors>
</system.web>
5. 真正全局可用的函数(App_Code)
// App_Code/MyHelpers.cshtml
@helper FormatMoney(decimal money) {
<span style="color:red">¥@money.ToString("N2")</span>
}
@helper IsActive(string current, string target) {
if(current == target) { <text>class="active"</text> }
}
页面里直接用:
@MyHelpers.FormatMoney(999.99)
<a href="/Products" @MyHelpers.IsActive(Request["page"], "Products")>产品</a>
终极总结:ASP.NET Web Pages 的「全局」文件一览表
| 文件名 | 放置位置 | 执行次数 | 主要职责 |
|---|---|---|---|
| _AppStart.cshtml | 根目录 | 应用启动时 1 次 | 数据库初始化、全局配置、路由注册 |
| _PageStart.cshtml | 根目录或子文件夹 | 每个请求前 | 登录检查、权限、公共数据注入 |
| _ViewStart.cshtml | 根目录或子文件夹 | 每个页面渲染前 | 指定 Layout |
| Web.config | 根目录 | – | 错误页、连接字符串、自定义路由 |
| App_Code 里的文件 | App_Code 文件夹 | 按需编译 | 全局函数、类、助手 |
只要掌握这 5 个“全局点”,你写的 ASP.NET Web Pages 项目就和 MVC 一样专业、健壮、可维护。
需要我给你一个包含全部这些全局文件的完整可运行模板项目(带后台、前台、登录、权限、错误处理)吗?压缩包 500KB,10 秒就能跑起来。