Wednesday, November 7, 2012

[C#] Custom Class in StateServer / SQLServer

這是最近遇到的一個問題,解決之後覺得有價值記錄一下,於是就來寫這篇了。

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),但是某些類別是無法序列化的,像是SessionStateSqlDataSource...都無法被序列化,另外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 List Member;
  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

2 comments:

  1. Il negozio ha risolto il problema per me e il servizio è molto paziente,replica alexander mcqueen questa è un'esperienza di acquisto perfetta. Quando ho ricevuto le scarpe alexander mcqueen, ho pensato che fosse una buona copia delle sneaker alexander mcqueen. Mi piace questo negozio online.uomo alexander mcqueen scarpe italy Queste scarpe alexander mcqueen sono semplici e generose. Molto soddisfatto di questo acquisto.

    ReplyDelete
  2. replica longines watches is not the oldest among Swiss watchmakers but it has proven that it is deserving of its stature. replica mens longines master collection watches Established in 1832, its legacy still lives on as among the most trusted of watch brands, promising both quality in make and refinement. This is evident in the La Grande Classique, made for both men and women. The restrained elegance is not foreign to the brand, but La Grande Classique offers this with a svelte case.

    ReplyDelete

Related Posts Plugin for WordPress, Blogger...