最近手头的一个ASP.Net的项目不时会出现编译错误,提示某个控件ascx类不存在,但该控件明明就在同一个网站下。错误有时候会突然出现,而一旦出现错误再多次编译也无法消除。由于公司使用脚本编译,而不是用msbuild或Visual Studio直接编译。事实上用Visual Studio编译从来没有出过错。用ProcExp看了一下build时编译时到底执行了什么:
主要就是这一条命令。难道是编译器有bug?再细究发现aspnet_compiler.exe又调用了csc.exe(C#编译器):
到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里):
但怎么决定文件的分组呢,哪些文件要放在前面的组,哪里文件要放在后面?我们在.aspx.xxx.compiled或.ascx.xxx.compiled里发现了该文件依赖于哪些文件的信息:
< 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:
page.PlaceHolder.Controls.Add(ctrl);