Inside ASP.NET 2.0-即时编译系统
文/ 黄忠成(原文刊登于Run! PC)
从ASP.NET 1.1 到2.0, 编译系统的进化
在笔者撰写『深入剖析ASP.NET 元件设计』一书时,曾相当深入的探讨ASP.NET 1.1 的即时编译模型, 该章节以图1 为开端, 一步步的将隐身于后的设计理念摊开在讀者面前,时至今日,ASP.NET即将迈入2.0 了,这个即时编译模型做了相当大幅度的变化, 图2 是对照1.1 与2.0 的即时编译模型概观,讀者们可以发现,2.0的即时编译模型复杂了许多。 图1
图2
在1.1 时,当访问者要求一个文件时,ISAPIRuntime(IIS 的要求处理物件) 会依照文件類型來唤起适当的Http Handler ,以.aspx 來說就是PageHandlerFactory, 她也是即时编译系统的入口, 这段流程在2.0 仍然没有改变,但后面的动作就完全变样了,在1.1 时, PageHandlerFactory 会使用PageParser 來解译.aspx 文件,再交由PageCompiler 來产生出编译档案。在2.0 时,同样的动作是交由BuildManager 來完成,其会呼叫适当的BuildProvider 來处理要求的文件, 最后交由适当的Compiler 來产生编译档案。不知讀者们是否看出上面这段话所隐含的意义,是的!BuildManager 具备依照不同附档名使用不同BuildProvider 的能力, 这代表着设计者可能拥有撰写自订的BuildProvider 來參与即时编译流程。讀者们可以在Visual Web Developer 的New Items 选项中看到图3 的画面。 图3
其中最引人注意的是ASP.NET 2.0 允许使用者撰写Generic Handler, 也就是1.1 中的自定Http Handler 程式档,该Wizard 会产生出程式1 的码。
程式1
<%@ WebHandler Language="C#" Class="Handler" %>
using System.Web;
public class Handler : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World");
}
public bool IsReusable {
get {
return false;
}
}
}
你是否看到了一个介于ASP.NET Script 与一般程式档的怪異程式码呢? 在存档后执行时会看到图4 的结果。
图4
问题來了, 以往撰写这种自定义的Http Handler 时,设计师必须预先将程式码编译好, 放置于网站目錄下, 这个Handler 才能正常运作, 但现在并未执行这个编译动作啊?那是谁为我们编译这个档案,又是如何做的呢? 答案与1.1 时相同,就是SimpleHandlerFactory, 但后面的动作就不同了, 以往的SimpleHandlerFactory 只是载入对应的Assembly 來启动Http Handler, 在2.0 时此动作换成了BuildManager, 她会寻找.ashx 对应的Build Provider,也就是WebHandlerBuildProvider 來运行即时编译模型。以上的讨論說明一件事,Handler Factory 的大部份工作已经下放给BuildManager 了, 而目的就是提供一个更强大的即时编译模型,不只是可以编译.aspx、.ascx, 还可以编译各式各样的文件,例如.masterpage 也是这个模型中的一员, 这带來了一个难以想象的极大优点,设计师以后将具备自定Script 文件的能力,只要有需求,设计师可以自行定义一种Script 语言,