這是最近遇到的一個問題,解決之後覺得有價值記錄一下,於是就來寫這篇了。
ASP.NET的 session state 有幾種模式可以設定
一般常用到的模式會是InProc、StateServer、SQLServer這三種(Custom先跳過不理),InProc預設值通常是不會遇到問題的,但是如果你在開發時有用一些Custom Class(或是某些特定類別),那在Session State改成StateServer/SQLServer(以下稱為Session Server)時,就會遇到下面這個錯誤。
英文版
原因是使用Session Server,ASP.NET必須將Session內容做序列化(Serialization),但是某些類別是無法序列化的,像是SessionState、SqlDataSource...都無法被序列化,另外Custom Class,因為ASP.NET不認得它,所以當然也不能自動的序列化放進session內,於是就會有上面那個錯誤。
以Custom Class來說,若Class內都是用一些簡單的型態像是String,Dictionary,List之類,這些ASP.NET都可以自動的做好序列化,那這時候在Class宣告上加上[Serializable]標記就好,這樣ASP.NET就會知道這個Custom Class是可序列化的物件,因而可以丟進Session。(簡單範例如下)
但是在一些情況下,例如Custom Class又包了Custom Class的時候,ASP.NET就沒辦法自動認得要如何序列化這些物件,就必須要自己去實做方法,才能正常的丟到Session內了。
實作的方法大概類似如上,簡單來說就只是幫ASP.NET做好進出session時該做什麼事而已。
如果你遇到的情況是在Session裡面又放了一些沒辦法序列化的.Net原生物件,那只好自己想辦法改結構,讓這些東西不放進去了(但是會花很久時間就是)
資料參考:
Session-State Modes
Custom Serialization
ASP.NET的 session state 有幾種模式可以設定
- InProc : 將session state存在那台web server的記憶體中。(預設值)
- StateServer : 將session stste存在特定的有開啟ASP.NET state service的機器上,這個模式在多台web server共用一台stste server的狀況下,可以在做web server重開、切換這些動作時,同時保持session存在,避免需要session的工作產生錯誤。
- SQLServer : 將session stste存到指定的SQL server中,效果同StateServer只是儲存媒體不同。
- Custom : 將session state存到自訂的儲存媒介內。
- Off : 不使用session
一般常用到的模式會是InProc、StateServer、SQLServer這三種(Custom先跳過不理),InProc預設值通常是不會遇到問題的,但是如果你在開發時有用一些Custom Class(或是某些特定類別),那在Session State改成StateServer/SQLServer(以下稱為Session Server)時,就會遇到下面這個錯誤。
英文版
Server Error in '/' Application.
Unable to serialize the session state. In 'StateServer' and 'SQLServer' mode, ASP.NET will serialize the session state objects, and as a result non-serializable objects or MarshalByRef objects are not permitted. The same restriction applies if similar serialization is done by the custom session state store in 'Custom' mode.
[SerializationException: Type 'MyCustomObj' in Assembly 'MyObj, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.]
'/' 應用程式中發生伺服器錯誤。
無法序列化工作階段狀態。在 'StateServer' 和 'SQLServer' 模式中,ASP.NET 將序列化工作階段狀態物件,因此不允許無法序列化的物件或 MarshalByRef 物件。在 'Custom' 模式中,自訂工作階段狀態存放區執行類似的序列化作業時,也會有同樣的限制。
[SerializationException: 未將型別 'MyCustomObj' (於組件 'MyObj, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' 中) 標記為可序列化。]
原因是使用Session Server,ASP.NET必須將Session內容做序列化(Serialization),但是某些類別是無法序列化的,像是SessionState、SqlDataSource...都無法被序列化,另外Custom Class,因為ASP.NET不認得它,所以當然也不能自動的序列化放進session內,於是就會有上面那個錯誤。
以Custom Class來說,若Class內都是用一些簡單的型態像是String,Dictionary,List之類,這些ASP.NET都可以自動的做好序列化,那這時候在Class宣告上加上[Serializable]標記就好,這樣ASP.NET就會知道這個Custom Class是可序列化的物件,因而可以丟進Session。(簡單範例如下)
[Serializable] public class MyCustomObj { public int n1; public int n2; public string str; }
但是在一些情況下,例如Custom Class又包了Custom Class的時候,ASP.NET就沒辦法自動認得要如何序列化這些物件,就必須要自己去實做方法,才能正常的丟到Session內了。
[Serializable] public class People { public int Age; public int ID; public string Name; } [Serializable] public class Department { public int BossID; public string Name; public ListMember; public void GetObjectData(SerializationInfo info, StreamingContext context) { info.AddValue("BossID", BossID); info.AddValue("Name", Name); info.AddValue("Member", Member); } protected Department(SerializationInfo info, StreamingContext context) { BossID= info.GetInt32("BossID"); Name= info.GetString("Name"); Member= (List )info.GetValue("Member", typeof(List )); }
實作的方法大概類似如上,簡單來說就只是幫ASP.NET做好進出session時該做什麼事而已。
如果你遇到的情況是在Session裡面又放了一些沒辦法序列化的.Net原生物件,那只好自己想辦法改結構,讓這些東西不放進去了(但是會花很久時間就是)
資料參考:
Session-State Modes
Custom Serialization
No comments:
Post a Comment