【小生雜談】ASP.Net_Compiler的編譯過程

iDotNetSpace發表於2008-07-23

最近手頭的一個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_.n.cs; (n=0~...)。如果網頁比較多的話,就會有多組App_Web_.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檔案裡的引用。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-407094/,如需轉載,請註明出處,否則將追究法律責任。

相關文章