65.9K
CodeProject 正在变化。 阅读更多。
Home

ASPX 文件背后的故事

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (29投票s)

2004 年 1 月 20 日

5分钟阅读

viewsIcon

200927

描述了 ASPX 文件所包含的内容以及 ASPX 文件如何影响页面生命周期。

引言

ASP.NET 页面通常由两个文件组成:ASPX 文件包含页面的可视化声明,而 *.cs 文件包含处理页面事件的代码(代码隐藏)。虽然所有 *.cs 文件都会编译成一个 DLL(以应用程序命名),并且 页面生命周期有详细文档记录,但 ASPX 文件的情况并非如此。

那些 ASPX 文件到底发生了什么?

那么,那些 ASPX 文件到底发生了什么?最终,ASP.NET 会将每个 ASPX 文件转换为一个程序集。虽然页面首次被称为 ASP.NET 时,这会导致

  1. 生成一个 *.cs 文件,其中包含与 ASPX 声明匹配的代码。
  2. 使用 csc.exe(C# 编译器)将 *.cs 文件编译成 DLL(如果您监视正在运行的进程,可以看到 csc.exe)。
  3. 运行编译后的 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 的文件夹,其中包含另一个目录:dl2dl2 文件夹包含随机编号的子文件夹,每个子文件夹对应 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 构造函数初始化类依赖文件。第一个被调用的函数是 FrameworkInitializeFrameworkInitializeTemplateControl 类中声明的受保护函数,并且仅在 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 文件所包含的内容后,我们应该回到页面生命周期并对其进行更新。此过程中有两个类:

  1. 代码隐藏类 - WebForm1
  2. 为 ASPX 文件生成的类 - adbdef

调用顺序为:

  1. 构造 adbdef
  2. 构造 WebForm1
  3. 将调用 adbdef 类的 FrameworkInitialize 方法。
  4. 调用 __ BuildTree 和其他控件生成函数。
  5. 按顺序调用页面和控件的事件。如果事件在 ASPX 文件和代码隐藏中都声明了,则 ASPX 事件将首先被调用,然后是代码隐藏事件。
© . All rights reserved.