ASP.NET Web Site專案在發佈(Publish)時有個選項"Allow this precompiled site to be updatable"(舊文參考),選取後,除了將所有.cs預先編譯成DLL外,發佈的.aspx內容也會被改成只有一行文字,純粹供IIS偵測檔案是否存在用:
"This is a marker file generated by the precompilation tool, and should not be deleted!"

而.aspx原本的HTML標籤、JavaScript等內容,其實已被編譯封裝進bin目錄的DLL中(全部編譯成一顆DLL或一個.aspx一顆DLL),而另外bin目錄會新增一個default.aspx.nnnnnnnn.compiled檔案(其中nnnnnnnn為8碼16進位雜湊碼,例如35f098fcf、538e2dd1),內容為XML,指出該aspx被儲存在哪一個組件的哪一個型別中,如下例:

<?xml version="1.0" encoding="utf-8"?>
<preserve resultType="3" virtualPath="/PreComWeb/Default.aspx" hash="35f098fcf" filehash="6bbd7e3038e2dd1" flags="100000" assembly="App_Web_vglx0yba" type="ASP.default_aspx">
    <filedeps>
        <filedep name="/PreComWeb/Default.aspx" />
        <filedep name="/PreComWeb/Default.aspx.cs" />
    </filedeps>
</preserve>

如此,即便只是網頁上HTML元素標籤或JavaScript、CSS Style的小修改,也必須修改原始程式後重新編譯、發佈,不可能直接編輯正式主機上的.aspx進行修改(如此亦可降低網頁被篡改的風險)。

若我們故意將bin/default.aspx.cdcab7d2.compiled刪除,則會出現以下錯誤:

The file '/precomweb/default.aspx' has not been pre-compiled, and cannot be requested.

少了compiled檔就找不到對應的aspx內容,很合理,到目前為止都符合我所理解的先行編譯網站運作原則。

不過,前幾天就遇上一枚離奇茶包。網站發佈到另一台主機後,部分網頁爆出以上訊息,直覺上是先行編譯的環節出了問題,於是仔細檢查了PrecompiledApp.config、bin下的相關*.aspx.nnnnnnnn.compiled與對應DLL都存在,怎麼都無法解釋為何ASP.NET一直抱怨預先編譯機制出錯。由於訊息中出現0x80004005(Access Denied),也使用了ProcMon監看,亦未發現任何讀寫檔案失敗的軌跡。

最後在一篇Microsoft Connect回報裡找到線索,

"It's a false error, indicative of a specific assembly it cannot load. To give you the specific one(s) it is having trouble with, clear out the entire compiled version and deploy your uncompiled code instead. Launch it and you should get the lovely yellow and white Server Error page telling you exactly what assembly it can't load. Figure out how to get that assembly loaded and repeat. Once your site comes up completely then wipe out the uncompiled version and replace with the precompiled version and you are all set."

意思是,這是個誤導效果十足的錯誤訊息,真正的錯誤可能源於該網頁執行時無法載入必要的組件,建議的解決方式是先部署非先行編譯的版本到該主機上,再執行同一網頁。此時應可看到一般的ASP.NET錯誤訊息回報,指出是哪顆DLL載入發生問題,排除後再重上預先編譯版本。在本案例中,使用前述做法,也真的找到了錯誤根源,網頁用了某個舊版DLL版本才有的方法,排除後問題即告解除。

試著重現及驗證此茶包:

  1. 新建立一個Web Site Project
  2. 利用NuGet加入JSON.NET
  3. 在Default.aspx.cs中加入以下程式
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using Newtonsoft.Json;
     
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            string r = JsonConvert.SerializeObject(DateTime.Now);
            Response.Write(r);
            Response.End();
        }
    }
  4. 發佈到新目錄F:\PreComWebPublish並掛上IIS
     
  5. 測試IIS上的網站正常
  6. 故意刪除bin/Newtonsoft.Json.dll
  7. 重測出現The file '/precomweb/default.aspx' has not been pre-compiled, and cannot be requested.
  8. 將未編譯過的default.aspx, default.aspx.cs複製到F:\PreComWebPublish並刪除PrecompiledApp.config,記得要IISRESET
  9. 錯誤訊息改變了,明確指出缺少Newtonsoft.Json

Comments

# by 91

隱藏版的錯誤訊息 XD

# by newbuy

今天也遇到這問題,結果是水晶報告的鍋

Post a comment