ASPX 文件背后的故事






4.56/5 (29投票s)
2004 年 1 月 20 日
5分钟阅读

200927
描述了 ASPX 文件所包含的内容以及 ASPX 文件如何影响页面生命周期。
引言
ASP.NET 页面通常由两个文件组成:ASPX 文件包含页面的可视化声明,而 *.cs 文件包含处理页面事件的代码(代码隐藏)。虽然所有 *.cs 文件都会编译成一个 DLL(以应用程序命名),并且 页面生命周期有详细文档记录,但 ASPX 文件的情况并非如此。
那些 ASPX 文件到底发生了什么?
那么,那些 ASPX 文件到底发生了什么?最终,ASP.NET 会将每个 ASPX 文件转换为一个程序集。虽然页面首次被称为 ASP.NET 时,这会导致
- 生成一个 *.cs 文件,其中包含与 ASPX 声明匹配的代码。
- 使用 csc.exe(C# 编译器)将 *.cs 文件编译成 DLL(如果您监视正在运行的进程,可以看到 csc.exe)。
- 运行编译后的 DLL。
这个序列只发生一次,生成一个 DLL,该 DLL 将用于其他请求,直到页面依赖文件中的任何一个被更改,从而导致序列重新执行。如果您曾经想知道为什么应用程序首次运行时会花费这么长时间,您可能已经有所了解了。
为了更好地理解这里发生了什么,让我们来看一个非常简单的页面并按照以下步骤进行。我创建了一个简单的页面,其中包含一个 Panel
、一个 Textbox
和位于 ASPX 文件中的服务器端脚本。下面您可以看到 ASPX 文件。
<%@ Import Namespace="System.Web" %>
<%@ Page language="c#" Codebehind="WebForm13.aspx.cs"
AutoEventWireup="false" Inherits="WebApplication22.WebForm13" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>WebForm13</title>
<meta content="Microsoft Visual Studio 7.0" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5"
name="vs_targetSchema">
</HEAD>
<body MS_POSITIONING="GridLayout">
<script language="C#" runat="server">
private void myfunc(object sender, System.EventArgs e)
{
HttpContext.Current.Response.Write("Text Init");
}
</script>
<form id="WebForm13" method="post" runat="server">
<asp:TextBox id="TextBox1" OnLoad="myfunc"
style="Z-INDEX: 101; LEFT: 101px; POSITION: absolute; TOP: 114px"
runat="server" Width="170px" Height="48px"></asp:TextBox>
<asp:Panel id="LblNav"
style="Z-INDEX: 102; LEFT: 22px; POSITION: absolute; TOP: 63px"
runat="server" Width="269px">Panel</asp:Panel>
</form>
</body>
</HTML>
ASP.NET 生成的所有文件将放置在此文件夹中:C:\$WINDOWSDir$\Microsoft.NET\Framework\v1.0.3705\Temporary ASP.NET Files\$YourWebAppName$\42343\654564。最后两个文件夹是 ASP.NET 随机生成的编号。趣味从最后一个目录开始。该文件夹保存为 ASPX 文件、ASCX 文件(用户控件)和 ASAX 文件生成的所有文件。最后一个文件夹还包含一个名为 Assembly 的文件夹,其中包含另一个目录:dl2。dl2 文件夹包含随机编号的子文件夹,每个子文件夹对应 Web 项目中的每个引用程序集,包括应用程序 DLL。我们将重点关注包含为 ASPX、ASCX 和 ASAX 文件生成的所有文件的文件夹。
我们首先感兴趣的是包含页面名称的 XML 文件(WebForm13.aspx.4689d8a0.xml)。此文件包含将 Web 页面名称映射到 ASP.NET 用于生成页面文件的随机名称的信息。除了映射信息外,该文件还包含有关该页面依赖文件的数据(任何对此文件的更改都会导致 ASPX 文件重新创建和重新编译)。
<preserve assem="jibrfh34" type="ASP.WebForm13_aspx" hash="49b238a170c332">
<filedep name="c:\inetpub\wwwroot\WebApplication22\bin\WebApplication22.DLL" />
<filedep name="c:\inetpub\wwwroot\WebApplication22\WebForm13.aspx" />
</preserve>
在理解了以“jibrfh34”开头的所有文件都是为特定页面生成的文件后,我们应该检查每个文件的用途。最重要的文件是 *.cs,它包含与 ASPX 标签和代码对应的生成的 C# 行,但我们稍后会回到这个问题。*.res 文件包含编译器将使用的资源。*.cmdline 包含 ASP.NET 用于编译 *.cs 文件的命令行。*.cmdline 文件包含对其他程序集和优化设置的引用。*.err 文件包含错误(如果在编译 *.cs 文件时发生)。*.out 文件包含编译过程的输出。*.dll 和 *.pdb 显然用作编译输出。
我们的下一步将是探索 *.cs 文件。
namespace ASP {
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Configuration;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Caching;
using System.Web.SessionState;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using ASP;
[System.Runtime.CompilerServices.CompilerGlobalScopeAttribute()]
public class WebForm13_aspx : WebApplication22.WebForm13,
System.Web.SessionState.IRequiresSessionState {
#line 19 "https:///WebApplication22/WebForm13.aspx"
protected System.Web.UI.HtmlControls.HtmlForm WebForm13;
#line default
private static bool __intialized = false;
private static object __stringResource;
private static System.Collections.ArrayList __fileDependencies;
#line 13 "https:///WebApplication22/WebForm13.aspx"
private void myfunc(object sender, System.EventArgs e)
{
HttpContext.Current.Response.Write("Text Init");
}
#line default
public WebForm13_aspx() {
System.Collections.ArrayList dependencies;
if ((ASP.WebForm13_aspx.__intialized == false)) {
ASP.WebForm13_aspx.__stringResource =
System.Web.UI.TemplateControl.ReadStringResource(typeof(ASP.WebForm13_aspx));
dependencies = new System.Collections.ArrayList();
dependencies.Add("c:\\inetpub\\wwwroot\\WebApplication22\\WebForm13.aspx");
ASP.WebForm13_aspx.__fileDependencies = dependencies;
ASP.WebForm13_aspx.__intialized = true;
}
this.Server.ScriptTimeout = 30000000;
}
protected override bool SupportAutoEvents {
get {
return false;
}
}
protected ASP.Global_asax ApplicationInstance {
get {
return ((ASP.Global_asax)(this.Context.ApplicationInstance));
}
}
public override string TemplateSourceDirectory {
get {
return "/WebApplication22";
}
}
private System.Web.UI.Control __BuildControlTextBox1() {
System.Web.UI.WebControls.TextBox __ctrl;
#line 20 "https:///WebApplication22/WebForm13.aspx"
__ctrl = new System.Web.UI.WebControls.TextBox();
#line default
this.TextBox1 = __ctrl;
#line 20 "https:///WebApplication22/WebForm13.aspx"
__ctrl.ID = "TextBox1";
#line default
#line 20 "https:///WebApplication22/WebForm13.aspx"
((System.Web.UI.IAttributeAccessor)(__ctrl)).SetAttribute("style",
"Z-INDEX: 101; LEFT: 101px; POSITION: absolute; TOP: 114px");
#line default
#line 20 "https:///WebApplication22/WebForm13.aspx"
__ctrl.Width = System.Web.UI.WebControls.Unit.Parse("170px",
System.Globalization.CultureInfo.InvariantCulture);
#line default
#line 20 "https:///WebApplication22/WebForm13.aspx"
__ctrl.Height = System.Web.UI.WebControls.Unit.Parse("48px",
System.Globalization.CultureInfo.InvariantCulture);
#line default
#line 20 "https:///WebApplication22/WebForm13.aspx"
__ctrl.Load -= new System.EventHandler(this.myfunc);
#line default
#line 20 "https:///WebApplication22/WebForm13.aspx"
__ctrl.Load += new System.EventHandler(this.myfunc);
#line default
return __ctrl;
}
private System.Web.UI.Control __BuildControlLblNav() {
System.Web.UI.WebControls.Panel __ctrl;
#line 21 "https:///WebApplication22/WebForm13.aspx"
__ctrl = new System.Web.UI.WebControls.Panel();
#line default
this.LblNav = __ctrl;
#line 21 "https:///WebApplication22/WebForm13.aspx"
__ctrl.ID = "LblNav";
#line default
#line 21 "https:///WebApplication22/WebForm13.aspx"
((System.Web.UI.IAttributeAccessor)(__ctrl)).SetAttribute("style",
"Z-INDEX: 102; LEFT: 22px; POSITION: absolute; TOP: 63px");
#line default
#line 21 "https:///WebApplication22/WebForm13.aspx"
__ctrl.Width = System.Web.UI.WebControls.Unit.Parse("269px",
System.Globalization.CultureInfo.InvariantCulture);
#line default
System.Web.UI.IParserAccessor __parser =
((System.Web.UI.IParserAccessor)(__ctrl));
#line 21 "https:///WebApplication22/WebForm13.aspx"
__parser.AddParsedSubObject(new System.Web.UI.LiteralControl("Panel"));
#line default
return __ctrl;
}
private System.Web.UI.Control __BuildControlWebForm13() {
System.Web.UI.HtmlControls.HtmlForm __ctrl;
#line 19 "https:///WebApplication22/WebForm13.aspx"
__ctrl = new System.Web.UI.HtmlControls.HtmlForm();
#line default
this.WebForm13 = __ctrl;
#line 19 "https:///WebApplication22/WebForm13.aspx"
__ctrl.ID = "WebForm13";
#line default
#line 19 "https:///WebApplication22/WebForm13.aspx"
__ctrl.Method = "post";
#line default
System.Web.UI.IParserAccessor __parser =
((System.Web.UI.IParserAccessor)(__ctrl));
#line 19 "https:///WebApplication22/WebForm13.aspx"
__parser.AddParsedSubObject(new
System.Web.UI.LiteralControl("\r\n\t\t\t"));
#line default
#line 19 "https:///WebApplication22/WebForm13.aspx"
this.__BuildControlTextBox1();
#line default
#line 19 "https:///WebApplication22/WebForm13.aspx"
__parser.AddParsedSubObject(this.TextBox1);
#line default
#line 19 "https:///WebApplication22/WebForm13.aspx"
__parser.AddParsedSubObject(new
System.Web.UI.LiteralControl("\r\n\t\t\t"));
#line default
#line 19 "https:///WebApplication22/WebForm13.aspx"
this.__BuildControlLblNav();
#line default
#line 19 "https:///WebApplication22/WebForm13.aspx"
__parser.AddParsedSubObject(this.LblNav);
#line default
#line 19 "https:///WebApplication22/WebForm13.aspx"
__parser.AddParsedSubObject(new
System.Web.UI.LiteralControl("\r\n\t\t"));
#line default
return __ctrl;
}
private void __BuildControlTree(System.Web.UI.Control __ctrl) {
System.Web.UI.IParserAccessor __parser =
((System.Web.UI.IParserAccessor)(__ctrl));
#line 1 "https:///WebApplication22/WebForm13.aspx"
__parser.AddParsedSubObject(this.CreateResourceBasedLiteralControl(0, 397, true));
#line default
#line 1 "https:///WebApplication22/WebForm13.aspx"
this.__BuildControlWebForm13();
#line default
#line 1 "https:///WebApplication22/WebForm13.aspx"
__parser.AddParsedSubObject(this.WebForm13);
#line default
#line 1 "https:///WebApplication22/WebForm13.aspx"
__parser.AddParsedSubObject(new
System.Web.UI.LiteralControl("\r\n\r\n\t</body>\r\n</HTML>\r\n"));
#line default
}
protected override void FrameworkInitialize() {
SetStringResourcePointer(ASP.WebForm13_aspx.__stringResource, 397);
this.__BuildControlTree(this);
this.FileDependencies = ASP.WebForm13_aspx.__fileDependencies;
this.EnableViewStateMac = true;
}
public override int GetTypeHashCode() {
return 423941586;
}
}
}
您可以注意到该文件包含映射代码与源 ASPX 文件中 HTML 行的注释。您可以使用这些行来了解 ASP.NET 如何转换 HTML 行,并从中学习很多东西。
每个生成的 *.cs 文件都是一个继承自代码隐藏类的类定义,并实现了一个接口。
public class WebForm13_aspx : WebApplication22.WebForm13
System.Web.SessionState.IRequiresSessionState
此类(WebForm13_aspx
)将在代码隐藏类(WebApplication22.WebForm13
)之前调用。显然,WebForm13_aspx
类的构造函数将首先被调用。WebForm13_aspx
构造函数初始化类依赖文件。第一个被调用的函数是 FrameworkInitialize
。FrameworkInitialize
是 TemplateControl
类中声明的受保护函数,并且仅在 ASPX 文件类中实现。FrameworkInitialize
调用 __BuildControlTree
,该函数负责创建所有页面控件。__BuildControlTree
调用 __ BuildControlWebForm13
,该函数创建 Form
并为 Form
上的每个控件调用 __BuildControlXXX
。如果控件包含子控件,则会调用相应子控件的 __BuildControlXXX
。每个 __BuildControlXXX
函数都通过相应控件的 ASPX 声明创建对象,设置其属性,并附加在 ASPX 文件上声明的所有事件。在 ASPX 文件中 SCRIPT
块内具有 runat
服务器属性设置为 true 的每个函数都生成为类方法,并在需要时连接到相应的委托。
如前所述,在 ASP.NET 首次调用页面时,*.CS 文件会被编译成程序集。我曾多次观察到对 ASPX 文件所做的更改未反映在发送到浏览器的 HTML 中。在这种情况下,删除 Temporary ASP.NET 下正确文件夹中的文件将解决问题,因为所有文件都将被重新创建。您还应该注意的一个问题是,C# 中控件初始化的事件不会发生在代码隐藏文件中,但在 ASPX 代码中却能完美工作。
在理解了 ASPX 文件所包含的内容后,我们应该回到页面生命周期并对其进行更新。此过程中有两个类:
- 代码隐藏类 -
WebForm1
。 - 为 ASPX 文件生成的类 -
adbdef
。
调用顺序为:
- 构造
adbdef
。 - 构造
WebForm1
。 - 将调用
adbdef
类的FrameworkInitialize
方法。 - 调用 __
BuildTree
和其他控件生成函数。 - 按顺序调用页面和控件的事件。如果事件在 ASPX 文件和代码隐藏中都声明了,则 ASPX 事件将首先被调用,然后是代码隐藏事件。