ASPNet_Compiler学习总结

ASPNet_Compiler的编译过程

http://www.cnblogs.com/wonderow/archive/2008/05/01/1178294.html
最近手头的一个ASP.Net的项目不时会出现编译错误,提示某个控件ascx类不存在,但该控件明明就在同一个网站下。错误有时候会突然出现,而一旦出现错误再多次编译也无法消除。由于公司使用脚本编译,而不是用msbuild或Visual Studio直接编译。事实上用Visual Studio编译从来没有出过错。用ProcExp看了一下build时编译时到底执行了什么:


aspnet_compiler.exe -d -v / -p <source webroot> <target webroot>
主要就是这一条命令。难道是编译器有bug?再细究发现aspnet_compiler.exe又调用了csc.exe(C#编译器):


 "C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc.exe" /noconfig /fullpaths @"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\1c85b622\f7798d18\mz_xtoba.cmdline"
到Temporary ASP.NET Files\root\1c85b622\f7798d18目录下查看,发现很多.cmdline, .err, .out, .compiled等文件,还有很多.cs文件!原来那些网页或AppCode下的.cs文件在这里被重组并分组了:App_Code.n.cs; App_Web_<xxx>.n.cs; (n=0~...)。如果网页比较多的话,就会有多组App_Web_<xxx>.n.cs。编译器会一组一组地编译n个cs文件,然后下一组的cs编译会引用上一组编译生成的DLL(在.cmdline里):


/t:library /utf8output /R:"System.Web.Services.dll" /R:"App_global.asax.dll" /R:"App_Web_rydiwb8f.dll"  /out:"App_Web_bl8pd2er.dll" App_Web_bl8pd2er.9.cs App_Web_bl8pd2er.0.cs  (已省略一些路径和参数。这里面App_Web_bl8pd2er.dll就引用了上一组cs生成的App_Web_rydiwb8f.dll)
但怎么决定文件的分组呢,哪些文件要放在前面的组,哪里文件要放在后面?我们在.aspx.xxx.compiled或.ascx.xxx.compiled里发现了该文件依赖于哪些文件的信息:


 <?xml version="1.0" encoding="utf-8"?>
<preserve resultType="3" virtualPath="/Result.aspx" hash="84d987223" filehash="a23fecda9fe4d6d8" flags="110000" assembly="App_Web_wt3qqawy" type="ASP.result_aspx">
    <filedeps>
        <filedep name="/controls/Control1.ascx" />
        <filedep name="/controls/Control1.ascx.cs" />
        <filedep name="/Result.aspx" />
        <filedep name="/Result.aspx.cs" />
    </filedeps>
</preserve>
于是猜想编译器就是在内存中维护用这样的依赖关系,并可以产生一个树来决定文件分组先后。但.compiled文件只在编译成功那个页面后才会生成。
明白了这些,再来找项目的问题:原来Result.aspx.cs里动态创建了Control2:


Control2 ctrl = (Control2)page.LoadControl("controls\\Control2.ascx");
page.PlaceHolder.Controls.Add(ctrl);
但在.compiled文件里看不到有这样的依赖关系!所以编译器不知道要把Control2.ascx分在Result.aspx的前一组。这样就会产生有时可以编译通过(刚好分对组了,上面的.compiled文件就是碰巧编译成功时的样子)有时出错的奇怪问题。解决方案也不难,就是在Result.aspx页面注册一下Control2控件:
<%@ Register TagPrefix="uc1" TagName="Control2" Src="controls\Control2.ascx" %>
即使aspx页面里没有直接引用该控件也要加这一行,让编译器知道该页面引用了控件。而文件依赖关系和.compiled文件正是使用了这个信息,编译器根本不看.cs文件里的引用。
========

关于ASP.NET预编译

http://www.cnblogs.com/dudu/archive/2011/02/07/aspnet_compiler_precompilation.html
为什么要用预编译?


博客园博客程序中.aspx和.ascx文件总共加起来有3000多个(博客模板中有大量的.ascx文件)。如果使用动态编译,每次只要更新bin文件夹中的任何一个dll文件,动态编译至少需要5分钟(访问量越高,所需的编译时间越长),而在动态编译期间网站访问速度极慢,几乎就是无法正常访问。这样,每次更新程序成为了一种痛苦,只能安排在深夜或一大早。


面对这样的情况,只能选择预编译。
预编译的原理是什么?
请阅读Artech写的深入剖析ASP.NET的编译原理之二:预编译(Precompilation)。
如何进行预编译?
用aspnet_compiler命令,命令示例:


aspnet_compiler -v \ -p G:\SourceWebSite G:\TargetWebsite -fixednames


参数说明:
-v \  要编译的虚拟路径,这里表示根路径。
-p G:\SourceWebSite 要编译的源Web项目所在文件夹。
G:\TargetWebsite 编译目标文件夹。
-fixednames 每个.aspx与.ascx文件都编译生成单独的dll文件,并使用固定文件名。


编译情况分析
1. 源文件夹中的所有.aspx, .ascx及App_Code中的.cs文件都会被编译。


2. 编译中遇到任何一个错误,会立即停止编译,并清空目标文件夹中已生成的文件;解决了引起编译错误的问题后,只能从头重新进行编译。出现编译警告,只提示,不影响正常编译。


3. 编译完成后,aspnet_compiler会将.aspx, .ascx, .cs之外的所有文件原封不动地复制至目标文件。(如果编译只是为了更新网站程序,这个操作显得多余。aspnet_compiler没有提供取消这个操作的参数)


4. 3000多个.aspx,.ascx文件,使用-fixednames编译,耗时30分钟左右;不使用-fixednames编译,只要6分钟。-fixednames编译本来是为了更新方便(每次编译生成的文件名相同,更新生产环境中的dll时直接覆盖就行),没想到这么慢。不用-fixednames编译,每次更新时,要先删除原来的文件,再复制。在生产环境中,这个操作会短暂影响网站的正常访问。


5. 预编译不会生成任何.ascx文件,也就是编译目标文件夹中没有任何.ascx文件。如果存在通过System.IO.File.Exists判断.ascx文件是否存在的代码,将不能按正常逻辑执行。解决方法是将.ascx文件复制到目标文件夹。


为什么不用“可更新的预编译(Updatable Pre-compilation)”


Updatable Pre-compilation只编译App_Code中的文件以及.aspx,.ascx的code behind文件,我们的Web项目类型是Web Application,code behind已经编译了,App_Code中也没有代码,相当于已经处于这种编译状态,但还是需要至少5分钟的动态编译时间。


这种编译方式只是减少了编译.cs文件的工作量,但每个.aspx,.ascx文件还是要动态编译,不能避免动态编译的性能问题。


Updatable Pre-compilation适用于App_Code中有大量代码(更新其中的文件会引起该文件夹中的所有文件重新编译),又不想用Non-updatable Pre-compilation的情况。


结论


面对这么多的.aspx,.ascx文件,只能选择预编译。-fixednames编译实在太慢,只能放弃。更新时只能先删除,再更新。虽然有些不足,但总比动态编译好。


当然,真正的解决之道是干掉模板中的那些.ascx文件。ASP.NET MVC会是救星吗?
========

用aspnet_compiler发布网站



http://www.educity.cn/develop/493536.html


  在 2.0模型中,vs2005已经完全脱离了编译而成为了一个彻底的ide.算是一个不小的改动。其中更是取消了有关Web Application的概念,使得习惯了vs2003的人刚开始的时候会有一些摸不着头脑。下面简单说一下我在使用过程中自己总结的,算是一点经验。


  新建web工程并且位置是文件系统的时候,vs2005只是帮你建好了一个sln文件,这个东西只是指引msbuild 如何进行编译的,过程是:ide 调用 msbuild ,msbuild解析sln文件,msbuild调用aspnet_compiler.exe进行网站的编译。所以aspnet_compiler.exe只是负责进行网站的编译的。


  预编译的概念在framework 1.1 里面就存在了,vs2003中的预编译指的是将页面对应的cs/vb文件与resx文件编译后统一集成到一个dll中放到bin目录下,将aspx文件直接拷贝过去。这样做会留下隐患,因为aspx文件就直接暴露在最后的发行包中,如果完全是codeb-behind模型还好,只能改改界面,如果采用了页面上的来生成页面,源代码就暴露了。针对这些问题,vs2005采用了一种新的模式。


  请参看ASP.NET 编译工具 (Aspnet_compiler.exe) 这篇文章了解对各种文件的处理方式。


  IDE发布:


  vs2005中选择 生成-〉发布网站,在对话框中的操作将映射到aspnet_compiler.exe的参数中,可更新的发布对应 -u,其他选项类似,请参考上面的文章了解。


  注意:发布时将忽略nfig中的debug?问骋簧晌薜魇孕畔⒌奈募?


  手工编译:


  简单说来,如果是无更新发布模式编译,appcode下面的class编译成dll放在bin下,页面内容清空位置不变作占位用,同时页面被编译成一个随机名称的dll,增加一个同piled文件到bin目录下,内容大概如下:


  <?xml version="1.0" encoding="utf-8"?>


  <preserve resultType="3" virtualPath="/Forum/AdminList.aspx" hash="6772609c3" filehash="49154463f1d6738c" flags="110000" assembly="App_Web_hmrycg3w" type="ASP.forum_adminlist_aspx">


  <filedeps>


  <filedep name="/Controls/footer.ascx" />


  <filedep name="/Controls/header.ascx" />


  <filedep name="/Forum/AdminList.aspx" />


  <filedep name="/Forum/AdminList.aspx.cs" />


  <filedep name="/Forum/menu.ascx" />


  <filedep name="/Forum/menu.ascx.cs" />


  </filedeps>


  </preserve>


  里面只是列出了页面上的customcontrol,这里已经完成了和masterfile的映射。这样最大限度的保护了页面的敏感信息,发布过的网站中只能看见一堆文件名了。可更新的发布模式与vs2003类似,页面就直接拷贝过来不予编译了。


  讲了一堆原理,下面说一下aspnet_compiler.exe的调用方法,这是我使用的例子


  我的开发目录是这样的


  Project/


  library/


  devroot/


  pubroot/


  proj.sln


  使用的命令如下:


  aspnet_compiler -v / -p .\devroot -f .\pubroot


  分析:


  -v / 指明了iis的虚拟目录


  -p .\devroot 表示代码实际位置


  .\pubroot 指明了要发布的位置


  -f 表示强制改写目标位置


  你还可以用-u来进行传统意义上的预编译,-d来插入编译符号。
========

使用aspnet_compiler.exe预编译网站

http://www.ixueyi.com/jingyan/103518.html


第一步:切换到aspnet_compiler.exe所在目录
在“命令提示符”下,切换到所在目录“c:\windows\microsoft\framework\v2.0.50727”。
第二步:运行aspnet_compiler.exe预编译
Aspnet_Compiler -v test c:\tmp\test
-v是虚拟目录参数,test为虚拟目录名称,而c:\tmp\test是指先行编译后的程序文件的目的位置。
第三步:使用预编译后的网站
将预编译后的test目录Copy到正式网页服务器,部署网站。
但要注意:aspnet_compiler.exe不会对静态文件如:Web.config、文本文件和图片文件等进行编译,所以像数据库连接字符串请用 aspnet_regiis.exe工具来进行加密。
网站预编译后,以后也不会触发重新动态编译,故请不要事后再加入新的.aspx文件,那样不会有任何作用。
也可通过ClientBuildManager类进行编译
string vdir = "/MyDataSource"; //虚拟目录名称
string srcLocation = "c:\\Inetpub\\wwwroot\\VS2005IDE"; //来源位置
string tarLocation = "c:\\tmp\\VS2005IDE"; //目标位置
System.Web.Compilation.ClientBuildManager cbm = new System.Web.Compilation.ClientBuildManager (vdir,srcLocation,tarLocation);
cbm.PrecompileApplication(); //预编译
========
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值