Introduction
ASP.NET pages are usually compound of two files: the ASPX which contains the page
visualization declaration and the *.cs which contains the code to handle page events
(Code behind). While all the *.cs files compile into one DLL (with the application name)
and
the page life cycle is well documented, this is not the case of ASPX files.
What has really happened to those ASPX files?
Well, what has really happened to those ASPX files? At the end of the day, ASP.NET
turns each ASPX file into assembly. While the page is termed for the first time
as ASP.NET, this leads to the:
- Generation of a *.cs file holding code that matches the ASPX declarations.
- Using of csc.exe (C# compiler) to compile *.cs file into DLL
(you can see csc.exe if you monitor running processes).
- Running of the compiled DLL
This sequence occurs just once then, resulting with DLL that will be used
for other requests until one of the page dependencies files will be changed
leading to the re-enforcement of the sequence. If you ever wonder why running
an application for the first time takes such a long while, you would probably
have some idea already.
To understand better what is going on here, let�s take a very simple page
and follow the following steps. I have created a simple page that holds a Panel
,
Textbox
and server side script inside an ASPX file. Below you can see the ASPX file:
<%@ 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>
All the files that ASP.NET generated will be placed in this folder:
C:\$WINDOWSDir$\Microsoft.NET\Framework\v1.0.3705\Temporary
ASP.NET Files\$YourWebAppName$\42343\654564. The last two folders
are randomly numbered, generated by ASP.NET. The fun begins from the last directory.
That folder holds all the files generated for ASPX files, ASCX files (user control)
and ASAX files. The last folder also contains a folder called Assembly that holds
another directory: dl2. The dl2 folder contains sub folders with randomly numbered
names each for every referenced assembly from the web project,
including the application DLL. We will focus on the folder that contains
all the files generated for ASPX, ASCX and ASAX files.
The first file that we�re interested in is the XML file holding the page name
(WebForm13.aspx.4689d8a0.xml). This file contains information that map between
the web page name and the random name that will be used by ASP.NET to generate
page files. Besides the mapping information, the file consists of data
on the decency files of that page (any changes of that file will cause recreation
of ASPX files and recompilation):
<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>
After understanding that every file starting with �jibrfh34� is a file
that was generated for a certain page, we should examine what is the purpose
of every file. The most important file is the *.cs which holds the generated
C# lines corresponding to the ASPX tags and code, but we will come back
to that later. The *.res file holds resources that the compiler will use then.
The *.cmdline holds the command line that will be used by ASP.NET to compile
the *.cs file. The *.cmdline file includes a reference to other assemblies
and optimization settings. The *.err file contains errors (if they occurred
while compiling the *.cs file). The *.out file consists of outputs from
the compilation process. The *.dll and *.pdb obviously function
as the compilation output.
Our next step will be then exploring the *.cs file:
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 "http://localhost/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 "http://localhost/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 "http://localhost/WebApplication22/WebForm13.aspx"
__ctrl = new System.Web.UI.WebControls.TextBox();
#line default
this.TextBox1 = __ctrl;
#line 20 "http://localhost/WebApplication22/WebForm13.aspx"
__ctrl.ID = "TextBox1";
#line default
#line 20 "http://localhost/WebApplication22/WebForm13.aspx"
((System.Web.UI.IAttributeAccessor)(__ctrl)).SetAttribute("style",
"Z-INDEX: 101; LEFT: 101px; POSITION: absolute; TOP: 114px");
#line default
#line 20 "http://localhost/WebApplication22/WebForm13.aspx"
__ctrl.Width = System.Web.UI.WebControls.Unit.Parse("170px",
System.Globalization.CultureInfo.InvariantCulture);
#line default
#line 20 "http://localhost/WebApplication22/WebForm13.aspx"
__ctrl.Height = System.Web.UI.WebControls.Unit.Parse("48px",
System.Globalization.CultureInfo.InvariantCulture);
#line default
#line 20 "http://localhost/WebApplication22/WebForm13.aspx"
__ctrl.Load -= new System.EventHandler(this.myfunc);
#line default
#line 20 "http://localhost/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 "http://localhost/WebApplication22/WebForm13.aspx"
__ctrl = new System.Web.UI.WebControls.Panel();
#line default
this.LblNav = __ctrl;
#line 21 "http://localhost/WebApplication22/WebForm13.aspx"
__ctrl.ID = "LblNav";
#line default
#line 21 "http://localhost/WebApplication22/WebForm13.aspx"
((System.Web.UI.IAttributeAccessor)(__ctrl)).SetAttribute("style",
"Z-INDEX: 102; LEFT: 22px; POSITION: absolute; TOP: 63px");
#line default
#line 21 "http://localhost/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 "http://localhost/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 "http://localhost/WebApplication22/WebForm13.aspx"
__ctrl = new System.Web.UI.HtmlControls.HtmlForm();
#line default
this.WebForm13 = __ctrl;
#line 19 "http://localhost/WebApplication22/WebForm13.aspx"
__ctrl.ID = "WebForm13";
#line default
#line 19 "http://localhost/WebApplication22/WebForm13.aspx"
__ctrl.Method = "post";
#line default
System.Web.UI.IParserAccessor __parser =
((System.Web.UI.IParserAccessor)(__ctrl));
#line 19 "http://localhost/WebApplication22/WebForm13.aspx"
__parser.AddParsedSubObject(new
System.Web.UI.LiteralControl("\r\n\t\t\t"));
#line default
#line 19 "http://localhost/WebApplication22/WebForm13.aspx"
this.__BuildControlTextBox1();
#line default
#line 19 "http://localhost/WebApplication22/WebForm13.aspx"
__parser.AddParsedSubObject(this.TextBox1);
#line default
#line 19 "http://localhost/WebApplication22/WebForm13.aspx"
__parser.AddParsedSubObject(new
System.Web.UI.LiteralControl("\r\n\t\t\t"));
#line default
#line 19 "http://localhost/WebApplication22/WebForm13.aspx"
this.__BuildControlLblNav();
#line default
#line 19 "http://localhost/WebApplication22/WebForm13.aspx"
__parser.AddParsedSubObject(this.LblNav);
#line default
#line 19 "http://localhost/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 "http://localhost/WebApplication22/WebForm13.aspx"
__parser.AddParsedSubObject(this.CreateResourceBasedLiteralControl(0, 397, true));
#line default
#line 1 "http://localhost/WebApplication22/WebForm13.aspx"
this.__BuildControlWebForm13();
#line default
#line 1 "http://localhost/WebApplication22/WebForm13.aspx"
__parser.AddParsedSubObject(this.WebForm13);
#line default
#line 1 "http://localhost/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;
}
}
}
You can notice that the file contains notes that map the code to the HTML lines
in the source ASPX file. You can use those lines to see how ASP.NET converts HTML
lines and learn a lot from it.
Every generated *.cs file is a definition of a class that inherits from the code
behind class and implement interface:
public class WebForm13_aspx : WebApplication22.WebForm13
System.Web.SessionState.IRequiresSessionState
This class (WebForm13_aspx
) will be called before the code behind class
(WebApplication22.WebForm13
). Obviously WebForm13_aspx
class constructor
will be called first. WebForm13_aspx
constructor initializes the
class dependencies files.
The first function to be called is FrameworkInitialize
. FrameworkInitialize
is
a protected
function declared in TemplateControl
class and implemented just in ASPX file classes.
FrameworkInitialize
calls __BuildControlTree
which is the function that is responsible
to create all the page controls. __BuildControlTree
calls __ BuildControlWebForm13
that creates the Form
and calls __BuildControlXXX
for every control on the
Form
.
If control holds child controls, a call will be made to the corresponding
__BuildControlXXX
of every child control. Every __BuildControlXXX
function
creates object by the ASPX declaration of the corresponding control, sets its attribute
and attaches all events that are declared on the ASPX file. Every function,
declared in ASPX file inside SCRIPT
block with runat
server attribute set to true,
generates as class method and connects to the corresponding delegate, if needed.
As I mentioned before, the *.CS file is compiled into assembly in the first
instance the ASP.NET is calling a page. More then once, I have observed that
changes made in the ASPX file are not reflected in the HTML send to the browser.
In such a scenario, deleting the files under the right folder under Temporary ASP.NET
will solve the problem since all the files will be recreated. Another issue that
you should be aware of is that the events of control initialization in C# do not happen
in the code behind file but work perfectly in the ASPX code.
After understanding what goes with ASPX files, we should go back to the page life
cycle and update it. There are two classes in that process:
- The code behind class �
WebForm1
.
- The generated class for ASPX file �
adbdef
.
The call orders are:
- Construction of
adbdef
.
- Construction of
WebForm1
.
FrameworkInitialize
method of adbdef
class will be called.
- Calling __
BuildTree
and other control build functions.
- Calling the Page and controls' events by their order. If event is declared
in ASPX file and code behind, the ASPX event will be called first followed
by the code behind event.