如果这个时候,你查看临时目录(Directory\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files)中该Website对应的子目录,已将会看到生成了一些列的文件。
3.Page最终被转化成什么?
我们现在来看看通过编译,一个Page到底转换成什么。我们以Part I/Page1为例。通过上面的Sampe,我们知道它最终变成了两个Type:Page1和part_i_page1_aspx。
下面是Page1的定义:
public class Page1 : Page, IRequiresSessionState
{
// Fields
protected HtmlForm form1;
// Methods
protected void Page_Load(object sender, EventArgs e) ]
{
base.Response.Write(Utility.ReflectAllAssmebly());
}
// Properties
protected HttpApplication ApplicationInstance
{
get
{
return this.Context.ApplicationInstance;
}
}
protected DefaultProfile Profile
{
get
{
return (DefaultProfile) this.Context.Profile;
}
}
}
下面是part_i_page1_aspx的定义
[CompilerGlobalScope]
public class part_i_page1_aspx : Page1, IHttpHandler
{
// Fields
private static object __fileDependencies;
private static bool __initialized;
// Methods
public part_i_page1_aspx();
private HtmlHead __BuildControl__control2();
private HtmlTitle __BuildControl__control3();
private HtmlLink __BuildControl__control4();
private HtmlForm __BuildControlform1();
private void __BuildControlTree(part_i_page1_aspx __ctrl);
protected override void FrameworkInitialize();
public override int GetTypeHashCode();
public override void ProcessRequest(HttpContext context);
}
在part_i_page1_aspx中定义了一个基于aspx的HttpHandler所需的所有操作,并且它继承了Page1。所以我们可以说Part I/Page1这个page 最终的体现为part_i_page1_aspx。进一步说,对Part I/Page1的Http Request,ASP.NET所要做的就是生成一个part_i_page1_aspx来Handle这个request就可以了。
4.FastObjectFactory
通过上面的一个简单的Sample,你已经看到每个Assembly中都会生成一个以FastObjectFactory作为前缀的Type。这是一个很重要的Type,从它的名称我们不难猜出它的作用:高效的生成对象。而生成的是什么样的对象呢?实际上就是基于每个aspx的Http request的Http handler,对于Part I/Page1就是我们上面一节分析的part_i_page1_aspx对象。
我们现在通过Reflector查看我们生成的App_Web_n1mhegpg中的FastObjectFactory_app_web_n1mhegpg是如何定义的。
internal class FastObjectFactory_app_web_n1mhegpg
{
// Methods
Private FastObjectFactory_app_web_n1mhegpg()
{
}
private static object Create_ASP_part_i_page1_aspx()
{
return new part_i_page1_aspx();
}
private static object Create_ASP_part_i_page2_aspx()
{
return new part_i_page2_aspx();
}
}
通过上面的Code,我们可以看到在FastObjectFactory中定义一系列的Create_ASP_XXX(后缀就是Page 编译生成的Type的名称)。通过这些方法,可以快速生成对一个的Page。至于为什么会叫作FastObjectFactory,我想是因为直接通过调用这个静态的方法快速地创建Page对象,从而避免使用Reflection的late binding带来的性能的影响吧。
5.Preservation Files
进行每一次编译,ASP.NET会生成一系列具有.compiled扩展名的保留文件(Preservation File)。这个文件非常重要,我们现在来深入介绍这个样一个文件。
Preservation File这个文件本质上是一个XML。它是基于每个Page的,也就是每个Page都会有一个这样的Preservation File. 无论Page对应的Directory是怎样的,与之对应的Preservation File总会保存在根目录下,所以必须有一种机制保持为处于不同Directory的Page生成的Preservation File具有不同的文件名,不管Page的名称是否一样。所以Preservation File采用下面的命名机制:
[ page ].aspx.[folder-hash].compiled
其中[ page ]是Page的名称,[folder-hash]是对page所在路径的Hash Value。这样做有两个好处。
1、保证处于同一级目录的所有Preservation File具有不同的文件名。
2、保证ASP.NET对于一个Http request可以找到Page对应的Preservation File。
下面这个Preservation File就是上面Sample中Part II/Page1.aspx对应的Preservation File,名称为
default2.aspx.cdcab7d2.compiled。我们来看看XML每个Item各代表什么意思。
<?xml version="1.0" encoding="utf-8"?>
<preserve resultType="3" virtualPath="/Artech.ASPNETDeployment/Part II/Page1.aspx" hash="fffffff75090c769" filehash="5f27fa390c45c52a" flags="110000" assembly="App_Web_hitlo3dt" type="ASP.part_ii_page1_aspx">
<filedeps>
<filedep name="/Artech.ASPNETDeployment/Part II/Page1.aspx" />
<filedep name="/Artech.ASPNETDeployment/Part II/Page1.aspx.cs" />
</filedeps>
</preserve>
有这段XML我们可以看到,所有的内容都包含在preserve XML element中,在他中间定义了几个重要的attribute.
1、virtualPath: Page的虚拟地址。
2、assembly:Assembly名称
3、Type:Page的编译后对应的Type(Http handler)。
4、hash: 一个代表本Preservation File状态的Hash value。
5、filehash: 一个代表本Dependent File状态的Hash value。
通过hash和filehash的缓存,ASP.NET可以判断自上一次使用以来,Preservation File和它所依赖的Dependent File是否被改动,如果真的被改动,将会重新编译。因为对于文件的任何改动都会导致该Hash value的改变。
此外,Preservation File的<filedeps>列出了所有依赖的文件,对于Page,一般是aspx和code behind。
6. 进一步剖析整个动态编译过程
现在我们来总结整个动态编译的过程:
Step1:当ASP.NET收到对于某个Page的Request,根据这个request对应的Url试着找到该page对应的Preservation File,如果没有找到,重新编译Page所在目录下的所有需要编译的文件,同时生成一些额外的文件,包括Preservation File。
Step2:然后解析这个Preservation File,通过hash和filehash判断文件自身或者是Dependent File是否在上一次编译之后进行过任何的修改,如果是的,则重新编译。然后重新执行Step2。
Step3:通过Preservation File 的assembly attribute Load对应的assembly(如果Assembly还没有被Load的话),通过type获知对应的aspx type,然后借助FastObjectFactory的对应的Create_ASP_XXX创建这个type。这个新创建的对象就是我们需要的Http Handler,在之上执行相应的操作把结果Response到客户端。