Inside ASP.NET 2.0-即时编译系统

<iframe align="top" marginwidth="0" marginheight="0" src="http://www.zealware.com/46860.html" frameborder="0" width="468" scrolling="no" height="60"></iframe>

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

<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path><lock v:ext="edit" aspectratio="t"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 415.5pt; HEIGHT: 4in" type="#_x0000_t75"><imagedata src="file:///C:%5CDOCUME~1%5CAdmin%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.jpg" o:title=""></imagedata></shape>

2



<shape id="_x0000_i1026" style="WIDTH: 415.5pt; HEIGHT: 401.25pt" type="#_x0000_t75"><imagedata src="file:///C:%5CDOCUME~1%5CAdmin%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image003.jpg" o:title=""></imagedata></shape>

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

<shape id="_x0000_i1027" style="WIDTH: 415.5pt; HEIGHT: 163.5pt" type="#_x0000_t75"><imagedata src="file:///C:%5CDOCUME~1%5CAdmin%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image005.jpg" o:title=""></imagedata></shape>

其中最引人注意的是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

<shape id="_x0000_i1028" style="WIDTH: 270.75pt; HEIGHT: 144.75pt" type="#_x0000_t75"><imagedata src="file:///C:%5CDOCUME~1%5CAdmin%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image006.jpg" o:title=""></imagedata></shape>

问题來了, 以往撰写这种自定义的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 语言, 再提供对应的BuildProvider 物件,BuildManager 将很意的为你完成即时编译动作,而且优点还只于此,BuildManager支援预编译模型, 也就是设计师只要提供Script 文件与BuildProvider 后, 就能享受即时编译与预编译种模型。举一个较实务的子, 一个设计师希望提供某种较简单的Script 语言供使用者应用, 那么该设计师只需提供一个MyScriptBuildProvider, 将其与特定的附档名对应之后, 再CodeDom 产生真正的程式码就可以,接下的动作BuildManager 将很意的帮你完成。

Reloaded! Page Compiler-Time

既然2.0 已经改变即时编译模型,那么就让我们从新解这个编译系统究竟是如何

动作的,在1.1 中,即时编译系统最人注意的是PageParser 物件,此物件会.aspx

文件,将其解译成一群Control Builder 物件交由PageCompiler 物件产生原始程式码后

编译,这段过程在2.0 中依然没变,同的是PageParser 2.0 中已经是由

PageHandlerFactory 呼叫,图5 2.0 Web Page 的编译时期概观。

5,一段算短的旅行景点, 在BuildManager 接到编译命时, 会先将目中的几个外部档案编译好, 这些档案就是Resource Web Reference Code Profile Global.asaxResource 指的是资源档,Web Reference 通常是引用Web Services 时用的档案,Code 是位于Code 下的程式档,Profile 则是位于web.config 中的Profile 区段定义,Global Asax 则是大家所熟悉的Global.asax 档案。接下是本节的重头戏Compiling Web Files!这个动作将会编译网站中的.aspx 或是其它拥有相对应BuildProvider 物件的档案,.ashx.masterpage 等等。回到Page 的编译周期上,.aspx 所对应的BuildProvider PageBuilderProvider 物件,此物件会使用PageParser 解译.as px,再PageCodeDomTreeGenerator 产生出原始码,最后交由适当的Compiler 编译。

<shape id="_x0000_i1029" style="WIDTH: 414.75pt; HEIGHT: 401.25pt" type="#_x0000_t75"><imagedata src="file:///C:%5CDOCUME~1%5CAdmin%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image007.jpg" o:title=""></imagedata></shape>

ManagerProvide rGenerator

承上节,BuildManagerBuildProvider 及其CodeGenerator 拥有可分的关系,图6 是目前2.0 所提供的一部份BuildProvider 物件,者们可以在其中发现许多熟悉的物件名称,她们就是对应到目前你能在ASP.NET 中撰写的文件。

6



<shape id="_x0000_i1030" style="WIDTH: 414.75pt; HEIGHT: 207pt" type="#_x0000_t75"><imagedata src="file:///C:%5CDOCUME~1%5CAdmin%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image009.jpg" o:title=""></imagedata></shape>

有趣的是Page Theme 居然也拥有一个PageThemeBuilderProvider, 这代表着么呢?笔者原以为Theme 只是一个简单的文字档,当Page 套用某一个Theme 时,只是由该文字档中取定义套用至控件上,但结果然, 由PageThemeBuilderProvider 的出现看,Theme 是一个编译后的文件,PageThemeBuilderProvider 会编译所有的Theme 档案, 也就是.skin,事实上,所有于内的控件定义都会被编译成控件实体,当Page 需要套用某个Theme 至控件时, 只是将控件的属性复制过, 没有解译动作, 速自然快上少。基本上,所有可编译型的BuildProvider 物件都会提供个物件,一个是Parser,用解译文件用, 另一个是CodeDomTreeGenerator, 用Control Builder 物件群转换为可编译的原始码, 以PageTheme 來說, 就如图7 所示。 图7

<shape id="_x0000_i1031" style="WIDTH: 415.5pt; HEIGHT: 142.5pt" type="#_x0000_t75"><imagedata src="file:///C:%5CDOCUME~1%5CAdmin%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image011.jpg" o:title=""></imagedata></shape>

当然,这并每一个BuildProvider 都得提供这些东西,约层仅到达BuildProvider 就停止, 只要该BuildProvider 能传回一个实体,BuildManager 管其内部是如何达到的。

预编译系统

截至目前为止, 我们一直在即时编译系统上打转, 并未谈到另一个系统, 那就是预编译系统, 事实上这个系统只是即时编译系统的一种呈现型式, 当BuildManager 启动时,会先判别要求的目中是否拥有.compiled 的档案, 存在的话就将其视为预编译模式, 载入.compiled 文件中所定义的Assembly, 等会!预编译后的档案真正的.aspx 存在BuildManager 如何做接下的动作,又是如何与BuildProviders 互动呢?哦, 没有!在预编译情况下,BuildManager 根本就会用到BuildProvider, 这跟即时编译系统的二次动作一样, 当即时编译系统完成后, 会将结果存放到暂存目中, 顺带着也会放一份到Cache 中, 待下次收到要求时, 就直接取用, 预编译系统只是跳过第一次那一段动作而已, 这代表着, 自定的BuildProvider 用做特别的动作, 就可以享受到预编译系统的优点。


Custom Build Provider

由于目前ASP.NET 2.0 仍处于Beta 版本,有关于Build Provider 的资讯少之又少,过我还是在文件中找到程式2 明。程式2

<configuration><span style="mso-spacerun: yes"> </span><system.web><compilation> …….</compilation></system.web></configuration>

<buildproviders><buildprovider extension=".mafx" type="BuildProviderType,&lt;span style=" mso-spacerun: yes></buildprovider></buildproviders>BuildProviderAssembly" />

粗体字的部份就是定义自定Build Provider 的地方,这可以证明在ASP.NET 2.0 中,设计师是被允许撰写Build Provider 的,过除这个文件外,我再也找深入的资讯,而很幸的, 这个文件有一个错误, 其中的buildProvider 定义是被接受的, 实际上的语法应该如程式3。程式3

compilation debug="true">
buildProviders>
add extension=".ppp"
type="TestBuildProvider.MyCSharpBuilder, TestBuildProvider"
appliesTo="Code"/>
buildProviders>
compilation>

extension 是定义此BuildProvider 对应至何种副档名,type 指的是BuildProvider Assembly Type, 最后的appliesTo 是代表着使用于何种模式, 有四个选择, 一是Code, 代表程式档, 二是Resource, 就是资源档, 三是Web, 代表着网页档案(.aspx.ascx…), 四是All, 代表任何型档案。要撰写BuildProvider者必须先准备Visual Studio 2005 Beta 或是Visual C# Express,这些工具才有提供Class Library Wizard ,否则就得使用Command Line 方式编译范例了,程式4 是我们的第一个BuildProvider 。程式4

#region Using directives using System; using System.Collections.Generic; using System.Text; using System.IO; using System.CodeDom; using System.CodeDom.Compiler; using System.Web.Compilation; #endregion

namespace TestBuildProvider

{ public class MyCSharpBuilder:BuildProvider {

public override void GenerateCode(AssemblyBuilder assemblyBuilder)

{ TextReader reader = base.OpenReader(); string scriptString = reader.ReadLine(); CodeCompileUnit unit = new CodeCompileUnit(); unit.Namespaces.Add(new CodeNamespace("TEST")); CodeTypeDeclaration class1 = new CodeTypeDeclaration("HelloClass"); class1.IsClass = true; CodeMemberMethod method1 = new CodeMemberMethod(); method1.Name = "SayHello"; method1.ReturnType = new CodeTypeReference("System.String"); method1.Statements.Add(new CodeMethodReturnStatement(

new CodePrimitiveExpression(scriptString))); method1.Attributes = MemberAttributes.Public; class1.Members.Add(method1); unit.Namespaces[0].Types.Add(class1); assemblyBuilder.AddCodeCompileUnit(this, unit);

}

}

}

让我稍微解释一下这个范, 程式中以CodeDom 产生出一个HelloClass 别,在其中加入一个方法:SayHello ,为其定义一个字型别的传回值,特别注意的是此值是由OpenReader 所传回的TextReader 的,OpenReader 会以TextReader 开启目前处的档案, 此中就是class1.ppp( 后详)。编译后将其复制到网站目中的bin 下,假设你的网站目下并没有bin ,那就自建一个吧。接着修改web.config 加入程式5 的定义。程式5

compilation debug="true">
buildProviders>
add extension=".ppp" type

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值