asp.net [前言:]ASP.NET是微軟提供的最新的開發基於Web的應用程式的技術。它提供了大量的比傳統ASP指令碼技術的好處,包括:
1)通過把UI表現層(presentation)與商業邏輯(business logic)分開建立了更好的開發結構;
2)使用完全編譯的代碼代替了傳統ASP的代碼翻譯;
3)它編譯特性與每個支援的方法協同,這意味著使用ASP.NET的網站比使用傳統的ASP網站的效能更高。
儘管把存在的ASP應用程式轉換到ASP.NET有很多潛在的好處,也有些ASP應用程式任務很重要並且複雜。轉換過程可能需要更多資源並給應用程式帶來更多風險。解決這些問題的途徑之一是同時運行ASP和ASP.NET應用程式,在一個時刻將一個對話轉換為ASP.NET。為了同時運行新舊程式,需要建立一個機制在傳統的ASP與ASP.NET間共用對話狀態。本文討論的是怎樣使用.NET架構組件的類和序列化特性共用狀態資訊。
概述
Cookie是Web應用程式識別使用者對話的最常用的方法,可以用於識別傳統的ASP和ASP.NET對話狀態。在ASP指令碼中狀態資訊儲存在記憶體中,不能與其它應用程式(例如ASP.NET)共用。如果對話狀態使用通用格式儲存在微軟SQL Server中,它就可以被傳統的ASP和ASP.NET共同訪問。
在本例中,名為mySession的Cookie用於識別使用者對話。當使用者對Web應用程式作出請求時,將為該使用者產生唯一的Cookie用於識別對話。在隨後的請求中,瀏覽器將該唯一的Cookie發送回伺服器用來識別對話。在被請求的Web頁載入前,一個自訂對象將使用該唯一的Cookie從SQL Server中重新載入使用者對話資料。通過自訂對象Web頁中的對話狀態是可以訪問的。Web請求完成後,如果請求終止,對話資料將儲存回SQL Server(見圖1)。
圖1.資料流簡單圖
ASP.NET實現
在ASP.NET中每一個Web頁都衍生自System.Web.UI.Page類。Page類集合了HttpSession對象的一個執行個體用於處理對話資料。在本例中,叫做SessionPage的自訂Page類來衍生自System.Web.UI.Page,提供了類似Page類的所有特性。唯一的區別是預設的HttpSession使用自訂的對話對象重載了(對執行個體變數使用new修改符,C#允許衍生的類隱藏基類的成員)。
public class SessionPage : System.Web.UI.Page
{
...
public new mySession Session = null;
...
}
自訂的對話類使用HybridDictionary對象來相應儲存記憶體中的對話狀態(HybridDictionary可用於處理任意數量的對話元素)。為了與傳統的ASP通用,該自訂對話對象將限制對話資料類型為字串型(預設的HttpSession允許對話儲存任意類型的資料,不能與傳統的ASP通用)。
[Serializable]
public class mySession
{
private HybridDictionary dic = new HybridDictionary();
public mySession()
{
}
public string this [string name]
{
get
{
return (string)dic[name.ToLower()];
}
set
{
dic[name.ToLower()] = value;
}
}
}
Page類為定製暴露了不同的事件和方法。特別是OnInit方法用於設定Page對象的初始化狀態。如果請求不包含名為mySession的Cookie,將為要求者產生一個新的mySession Cookie。另外,對話資料將使用自訂Data Access ObjectsSessionPersistence從SQL Server中檢索出來。DSN和SessionExpiration的值從web.config中檢索。
override protected void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}
private void InitializeComponent()
{
cookie = this.Request.Cookies[sessionPersistence.SessionID];
if (cookie == null)
{
Session = new mySession();
CreateNewSessionCookie();
IsNewSession = true;
}
else
Session = sessionPersistence.LoadSession(
Server.UrlDecode(cookie.Value).ToLower().Trim(),
dsn,
SessionExpiration
);
this.Unload += new EventHandler(this.PersistSession);
}
private void CreateNewSessionCookie()
{
cookie = new HttpCookie(sessionPersistence.SessionID,
sessionPersistence.GenerateKey());
this.Response.Cookies.Add(cookie);
}
SessionPersistence類使用微軟.NET架構組件的BinaryFormatter來序列化和並行化對話狀態為二進位格式以提供最佳效能。結果的二進位對話資料接著作為圖象欄位類型被存入SQL Server。
public mySession LoadSession(string key, string dsn,
int SessionExpiration)
{
SqlConnection conn = new SqlConnection(dsn);
SqlCommand LoadCmd = new SqlCommand();
LoadCmd.CommandText = command;
LoadCmd.Connection = conn;
SqlDataReader reader = null;
mySession Session = null;
try
{
LoadCmd.Parameters.Add("@ID", new Guid(key));
conn.Open();
reader = LoadCmd.ExecuteReader();
if (reader.Read())
{
DateTime LastAccessed =reader.GetDateTime(1).AddMinutes(SessionExpiration);
if (LastAccessed >= DateTime.Now)
Session = Deserialize((Byte[])reader["Data"]);
}
}
finally
{
if (reader != null)
reader.Close();
if (conn != null)
conn.Close();
}
return Session;
}
private mySession Deserialize(Byte[] state)
{
if (state == null) return null;
mySession Session = null;
Stream stream = null;
try
{
stream = new MemoryStream();
stream.Write(state, 0, state.Length);
stream.Position = 0;
IFormatter formatter = new BinaryFormatter();
Session = (mySession)formatter.Deserialize(stream);
}
finally
{
if (stream != null)
stream.Close();
}
return Session;
}
在請求的末尾,Page類的Unload事件被啟動了,一個同Unload事件一起註冊的事件處理方法將序列化對話資料為二進位格式並將結果位元據存入SQL Server。
private void PersistSession(Object obj, System.EventArgs arg)
{ sessionPersistence.SaveSession(
Server.UrlDecode(coo