为什么要用预编译?
博客园博客程序中.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会是救星吗?
或者:(只编译修改的文件)
<compilation debug="true" batch="false" optimizeCompilations="true" targetFramework="4.5.1">
.