二進位度序列化碰到的問題—- 切實認識Asp.net2.0頁面編譯機制

來源:互聯網
上載者:User

 

 問題描述  

 手上有一行業門戶網站,每個使用者都有一個子網站(或說模板),每個子站會有一些配置資料(如:logo,橫欄圖片或者其它一些沒想到的東西)為了編程方便以及日後擴充方便,我使用直接在.aspx檔案中定義的類來儲存這些資料,同樣為了修改方便(編譯一次站的時間已經到了讓人無法接受地步),我這裡使用的是單獨的.aspx檔案(不關聯.cs檔案),配置資料會被分配給定義的類,然後將類序列化,使用是則執行還原序列化,(基本上也就類似那個profile的過程)

 

 下面是序列化代碼

 

public static class SerializationHelper
{
    public static string Serialize(object data)
    {

        using (MemoryStream streamMemory = new MemoryStream())
        {
            BinaryFormatter formatter = new BinaryFormatter();

            // 2. Serialize the dataset object using the binary formatter
            formatter.Serialize(streamMemory, data);

            // 3. Encrypt the binary data
            string binaryData = Convert.ToBase64String(streamMemory.GetBuffer());

            // 4. Write the data to a file
            return binaryData;
        }

    }

    public static object Deserialize(string serialData)
    {
        object data = new object();
        try
        {
            MemoryStream streamMemory;
            BinaryFormatter formatter = new BinaryFormatter();

            // 2. Read the binary data, and convert it to a string
            string cipherData = serialData;

            // 3. Decrypt the binary data
            byte[] binaryData = Convert.FromBase64String(cipherData);

            // 4. Rehydrate the dataset
            streamMemory = new MemoryStream(binaryData);
            data = formatter.Deserialize(streamMemory);
        }
        catch(Exception ex)
        {
            // data could not be deserialized
            data = null;
        }

        return data;
    }
}

 

這裡使用了二進位序列化,現有如下兩個檔案TemplateConfig.aspx跟Index.aspx.

 

TemplateConfig.aspx檔案裡面代碼如下

<script runat="server">

 

   //配置資料保持類的定義

   [Serializable]
    public class Temp_EntProperty
    {
        private string _bar;
        private string _logo;
        private System.Collections.Generic.List<SubItem> size;
        public System.Collections.Generic.List<SubItem> Size
        {
            get
            {
                if (size == null)
                {
                    size = new System.Collections.Generic.List<SubItem>();
                }
                return size;
            }

        }
        public string Bar
        {
            get { return _bar; }
            set { _bar = value; }
        }
        public string Logo
        {
            get { return _logo; }
            set { _logo = value; }
        }
    }

    [Serializable]
    public class SubItem
    {
        public SubItem(string name, int value)
        {
            _name = name;
            _value = value;
        }
        private string _name;
        private int _value;
        public string Name
        {
            get { return _name; }
            set { _name = value; }
              
        }
        public int Value
        {
            get { return _value; }
            set { _value = value; }
        }
    }

   protected void Buttion1_Click(object sender, EventArgs e)
    {

      

         Temp_EntProperty properties = new Temp_EntProperty();

         config.SerializeData = SerializationHelper.Serialize(properties); //將序列化後的資料儲存到資料庫

         //資料庫操作....

    }
</script>

 頁面標籤省略.......

 

Index.aspx檔案代碼如下

 

需要引用TemplateConfig.aspx頁

<%@ Reference Page="~/TemplateConfig.aspx" %>

<script runat="server">

     protected void Page_Load(object sender, EventArgs e)
    {

       ASP.templateconfig_aspx.Temp_EntProperty properties=SerializationHelper.Deserialize(serialData) as ASP.templateconfig_aspx.Temp_EnterProperty ;

       //serialData是資料庫中的序列化後資料.

    }

</script>

頁面標籤省略.......

 

 

 

這個過程很多時候都能正常工作(現在知道,這是3種情況中的一種)

第一種:我先運行了TemplateConfig.aspx檔案,然後再運行Index.aspx檔案發現一切正常.

 

第二種:我修改了一下TemplateConfig.aspx檔案,接著再次運行Index.aspx檔案時卻出現錯誤.

單步調試發現還原序列化是正常的,但是在將還原序列化後的object類型的執行個體轉化為Temp_EntProperty時出問題了,

單步調試明明顯示Object類型的執行個體就是Temp_EntProperty,但是卻不允許轉化....

 

第三種:有時候還會碰到還原序列化錯誤,提示找不到程式集,而奇怪的是,TemplateConfig.aspx跟Index.aspx檔案的代碼一行沒變動過.

 

問題的解決

當然這個3個問題不是同發現的,事實上這些問題是在網站測試的個把月中陸續發現的,為了避免這些情況,我一度把自訂類(如Temp_EntProperty等)改成Hashtable ,因為Hashtable不會出現以上問題,直到今天回過頭來認真的找下原因.

 

根據錯誤資訊大致可以判斷出是還原序列化時程式集問題(根據第三種情況),實際上以上問題的根源是,在.aspx檔案中定義的類是動態編譯的,其產生的程式集儲存在系統硬碟的.net目錄中(可以使用HttpRuntime.CodegenDir找到這個目錄),你每次對.aspx檔案的修改多會迫使asp.net運行時再次編譯這個類,產生新的程式集(以App_Web_開頭),而二進位序列化跟還原序列化是跟程式集相關的,即使用二進位序列化後的資料裡面保留了程式集資訊,而還原序列化時會根據這些資訊找到對應的程式集,完成還原序列化工作,另一方面Asp.net頁面編譯模型中,當頁面改變後,運行時產生新的頁面程式集,會有一種機制來刪除舊的頁面程式集.

拿TemplateConfig.aspx頁面為例, 當第一次運行時,系統在臨時目錄中產生其對應 App_Web_2342usaj(注意副檔名是.dll,這裡省略,下同) 程式集,接著你修改了這個TemplateConfig.aspx頁面(打個空格什麼的儲存下就好),你第二次請求時,運行時又會產生App_Web_asdfasd程式集,並且運行時試圖刪除App_Web_2342usaj程式集,但是不幸的是App_Web2342usaj程式集中已經被架載到AppDomain中了,Asp.net運行時無法刪除已經架載到AppDomain中的程式集,除非你重新啟動應用程式(修該下web.config或global.asax,重新啟動IIS或應用程式集區,當然重啟電腦也可以), 在無法刪除的情況下,Asp.net運行時會在臨時目錄下添加一個名為App_Web_2342usaj.dll.delete的空檔案,這是一個標記,在應用程式重新啟動時,AppDomain會被重新載入,而在載入之前,App_Web_2342usaj.dll檔案會被刪除,另外當你連續15次修改TemplateConfig.aspx檔案後,應用程式也會重新啟動,不然AppDomain中就會有太多程式集而消耗記憶體(參考Asp.net2.0進階編程),另外關於在頁面中使用Reference後,在觀察Index.aspx對應的.compiled檔案(臨時目錄下),可以發現在index.aspx.2342s.compiled(中間數字或字元是隨機)的<filedeps>節中有對檔案TemplateConfig.aspx的引用,這個說明在修改了TemplateConfig.aspx檔案後或觸發index.aspx依賴緩衝清除,也就是index.aspx會隨之重新編譯產生新的程式集.上面這些過程你也可以自己觀察到.

 

 好了有了上面這些知識我們現在可以解釋前面的三種情況了

 第二種情況,我們修改了一下TemplateConfig.aspx檔案後接著運行Index.aspx檔案,由於Index.aspx依賴於TemplateConfig.aspx檔案,因此TemplateConfig.aspx檔案跟Index.aspx檔案都會被重新編譯產生新的程式集,問題在於 index.aspx 代碼中

 

     protected void Page_Load(object sender, EventArgs e)
    {

       ASP.templateconfig_aspx.Temp_EntProperty properties=SerializationHelper.Deserialize(serialData) as ASP.templateconfig_aspx.Temp_EnterProperty ;

       //serialData是資料庫中的序列化後資料.

    }

使用的serialData是原先Temp_EntProperty程式集序列化的資料,因此在還原時由於老的程式集也還在AppDomain中,故還原序列化是成功的,但是轉化卻失敗了,原因是兩個類是同名類,但是位於不同的程式集中,如果我們這個時候重新啟動下應用程式,那麼就會出現第三種情況。

 

第三種情況:在應用程式重新啟動後,老的程式集會被刪除,而資料庫裡儲存的恰是舊程式集中Temp_EntProperty類的序列化後的資料(其中含舊程式集名稱),應次在你進行還原序列化時無疑會碰到程式集無法找到問題.

 

 問題找到了,那麼如何解決呢,其實也很簡單,如果你需要二進位序列化帶來的高效能跟資料量少的優勢,那麼就把需要序列化的類放到固定的程式集中(獨立建立一個項目), 如果你想在.aspx頁面中直接定義需要序列化的類,那麼你只能使用xml序列化,因為xml序列化後的資料不保留程式集資訊.

 

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.