Session失效目的是为了清空不使用的数据。
但有些特殊场合,我们并不想让Session失效。
比如一个系统中一个画面的内容特多,需要很长时间才能录入完了,而且录入的数据要更新的话,会用到很多Session里的值。
如果录入一半,突然有其他事情需要紧急处理去了。那这些录入的数据可能没等他回来就已经因Session失效而无法登录了。
对于这种情况,可以在Session失效的时候,把Session的值序列化,并保存到磁盘上,这样就不占用内存了。
等SessionStart时,判断一下保存的文件是否与当前的SessionID吻合,如果吻合,则反序列化,并重新赋值给Session。
这时的Session值就与Session失效前一样了。
序列化和反序列化的类为SessionStateItemCollection
示例:
Code
using System;
using System.Web;
using System.Web.SessionState;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Web.Configuration;
using System.Configuration;
using System.IO;
using System.Reflection;
using log4net;
namespace RealEstate.Common.Session
{
public class SessionMonitor
{
/// <summary>
/// ログ情報
/// </summary>
private ILog _log = LogManager.GetLogger("RealEstate.Common.Session.SessionMonitor");
private Dictionary<string , SessionInfo> m_SessionInfoList = null;
private string m_SessionDataSavePath = @"c:\Temp";
private static SessionMonitor sessionMonitor = null;
public static SessionMonitor GetSessionMonitor()
{
if (sessionMonitor == null)
{
sessionMonitor = new SessionMonitor();
}
return sessionMonitor;
}
public SessionMonitor()
{
this.m_SessionInfoList = new Dictionary<string, SessionInfo>();
sessionMonitor = this;
}
public SessionMonitor(string pSessionDataSavePath):this()
{
this.m_SessionDataSavePath = pSessionDataSavePath;
}
public bool IsG2001Login(string pSessionID)
{
bool vIsExisted = false;
if (this.m_SessionInfoList.ContainsKey(pSessionID))
{
vIsExisted = this.m_SessionInfoList[pSessionID].IsG2001Login;
}
return vIsExisted;
}
/// <summary>
///
/// </summary>
/// <param name="pSessionID"></param>
/// <param name="pIsLogin"></param>
/// <param name="isForced">ログアウトする時、正常にログアウトなら、trueをセットする、以外はfalseをセットする</param>
public void SetG2001Login(string pSessionID, bool pIsLogin, HttpSessionState pSession)
{
if (pIsLogin)
{
_log.Info("G2001ページを利用します。SessionID=" + pSessionID);
}
else
{
if (pSession == null)
{
_log.Info("G2001ページを閉めた。SessionID=" + pSessionID);
}
else
{
_log.Info("セッションはタイムアウトしました。G2001ページが開いているのため、サーバのディスクに保存する。SessionID=" + pSessionID);
}
}
if (this.m_SessionInfoList.ContainsKey(pSessionID))
{
SessionInfo vInfo = null;
bool vIsG2001Existed = false;
SessionStateModule vModule = null;
lock (this)
{
vInfo = this.m_SessionInfoList[pSessionID];
vIsG2001Existed = this.m_SessionInfoList[pSessionID].IsG2001Login;
vInfo.SetG2001Login(pIsLogin);
if (!pIsLogin)
{
this.m_SessionInfoList.Remove(pSessionID);
}
}
if (!pIsLogin)
{
if (vIsG2001Existed && pSession != null)
{
this.WriteSessionDataToFile(pSessionID, GetSessionData(pSession));
}
}
}
}
/// <summary>
/// Session.IsNewSessionの場合のみこのメソッドを処理する
/// </summary>
/// <param name="pSessionID"></param>
public void AddSession(string pSessionID)
{
_log.Info("新なセッションを開始します。SessionID=" + pSessionID);
SessionInfo vInfo = new SessionInfo(pSessionID);
string vFileName = GetSessionFilePath(pSessionID);
if (!string.IsNullOrEmpty(vFileName))
{
ReadSessionDataFromFile(vFileName);
//セッションファイルが存在する場合、必ずG2001画面が開いた。
vInfo.SetG2001Login(true);
}
this.m_SessionInfoList.Add(pSessionID, vInfo);
}
private SessionStateItemCollection GetSessionData(HttpSessionState pSession)
{
if (pSession == null)
{
return null;
}
//Type vModule = pModule.GetType();
//FieldInfo vSessionDataField = vModule.GetField("_rqItem", BindingFlags.NonPublic | BindingFlags.Instance);
//SessionStateStoreData vData = (SessionStateStoreData)vSessionDataField.GetValue(pModule);
//if (vData == null)
//{
// return null;
//}
SessionStateItemCollection vData = new SessionStateItemCollection();
foreach (string key in pSession.Keys)
{
vData[key] = pSession[key];
}
return vData;
}
private string GetSessionFilePath(string pSessionID)
{
if (!Directory.Exists(this.m_SessionDataSavePath))
{
return "";
}
string[] vFiles = Directory.GetFiles(this.m_SessionDataSavePath, string.Format("{0}.data", pSessionID));
if (vFiles.Length == 0)
{
return "";
}
return vFiles[0];
}
private void WriteSessionDataToFile(string pSessionID, SessionStateItemCollection pList)
{
if (pList == null)
{
return;
}
string vFileName = GetSessionFilePath(pSessionID);
if (vFileName != "")
{
File.Delete(vFileName);
}
if (!Directory.Exists(this.m_SessionDataSavePath))
{
return;
}
try
{
vFileName = string.Format("{0}{1}{2}.data", this.m_SessionDataSavePath, this.m_SessionDataSavePath.EndsWith(@"\") ? "" : @"\", pSessionID);
FileStream vStream = new FileStream(vFileName, FileMode.Create, FileAccess.Write);
BinaryWriter vWriter = new BinaryWriter(vStream);
pList.Serialize(vWriter);
vWriter.Close();
vStream.Close();
vStream.Dispose();
_log.Info("セッションデータをサーバのディスクへ保存する。SessionID=" + pSessionID);
}
catch (Exception ex)
{
this._log.Error("セッションのデータをサーバのディスクに保存する時、エラーを発生しました。", ex);
}
}
private void ReadSessionDataFromFile(string pFileName)
{
if (!File.Exists(pFileName))
{
return;
}
SessionStateItemCollection vList = null;
try
{
FileStream vStream = new FileStream(pFileName, FileMode.Open, FileAccess.Read);
BinaryReader vReader = new BinaryReader(vStream);
vList = SessionStateItemCollection.Deserialize(vReader);
vReader.Close();
vStream.Close();
vStream.Dispose();
//データ読み取ると、ディスクから削除する
File.Delete(pFileName);
}
catch(Exception ex)
{
this._log.Error("サーバのディスクからセッションデータを読み取る時、エラーを発生しました。", ex);
}
if (vList != null)
{
try
{
HttpSessionState vSession = HttpContext.Current.Session;
_log.Info("セッションデータをサーバのディスクから読み込む。SessionID=" + vSession.SessionID);
foreach (string key in vList.Keys)
{
vSession[key] = vList[key];
}
}
catch (Exception ex)
{
this._log.Error("サーバのディスクからのセッションデータをセッションにセットする時、エラーを発生しました。", ex);
}
}
}
}
public class SessionInfo
{
private string m_SessionID = null;
private DateTime? m_SessionStartTime;
private bool m_IsG2001Login = false;
public bool IsG2001Login
{
get
{
return this.m_IsG2001Login;
}
}
public SessionInfo(string pSessionID)
{
this.m_SessionStartTime = DateTime.Now;
this.m_SessionID = pSessionID;
}
private void CheckWhetherG2001Existed()
{
//G2001を閉じるの操作方法は六つかある
//①画面の閉じるボタンで閉じる
//②画面の×ボタンで閉じる
//③エラー発生する時、ApplicationManagement.UserLogoutを呼び出して、全て画面を閉じる
//④G2001の子画面がある場合、セッションをタイムアウトする時、Session_Endメソッドでクリアする
//⑤同一ユーザで一回以上登録でログアウトされた場合、FormBase.Page_Loadでクリアする
//⑥手動的にシステムのタスクマネージャで終了なら、Session_Endでクリアする
}
public void SetG2001Login(bool isLogin)
{
this.m_IsG2001Login = isLogin;
}
}
}
using System;
using System.Web;
using System.Web.SessionState;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Web.Configuration;
using System.Configuration;
using System.IO;
using System.Reflection;
using log4net;
namespace RealEstate.Common.Session
{
public class SessionMonitor
{
/// <summary>
/// ログ情報
/// </summary>
private ILog _log = LogManager.GetLogger("RealEstate.Common.Session.SessionMonitor");
private Dictionary<string , SessionInfo> m_SessionInfoList = null;
private string m_SessionDataSavePath = @"c:\Temp";
private static SessionMonitor sessionMonitor = null;
public static SessionMonitor GetSessionMonitor()
{
if (sessionMonitor == null)
{
sessionMonitor = new SessionMonitor();
}
return sessionMonitor;
}
public SessionMonitor()
{
this.m_SessionInfoList = new Dictionary<string, SessionInfo>();
sessionMonitor = this;
}
public SessionMonitor(string pSessionDataSavePath):this()
{
this.m_SessionDataSavePath = pSessionDataSavePath;
}
public bool IsG2001Login(string pSessionID)
{
bool vIsExisted = false;
if (this.m_SessionInfoList.ContainsKey(pSessionID))
{
vIsExisted = this.m_SessionInfoList[pSessionID].IsG2001Login;
}
return vIsExisted;
}
/// <summary>
///
/// </summary>
/// <param name="pSessionID"></param>
/// <param name="pIsLogin"></param>
/// <param name="isForced">ログアウトする時、正常にログアウトなら、trueをセットする、以外はfalseをセットする</param>
public void SetG2001Login(string pSessionID, bool pIsLogin, HttpSessionState pSession)
{
if (pIsLogin)
{
_log.Info("G2001ページを利用します。SessionID=" + pSessionID);
}
else
{
if (pSession == null)
{
_log.Info("G2001ページを閉めた。SessionID=" + pSessionID);
}
else
{
_log.Info("セッションはタイムアウトしました。G2001ページが開いているのため、サーバのディスクに保存する。SessionID=" + pSessionID);
}
}
if (this.m_SessionInfoList.ContainsKey(pSessionID))
{
SessionInfo vInfo = null;
bool vIsG2001Existed = false;
SessionStateModule vModule = null;
lock (this)
{
vInfo = this.m_SessionInfoList[pSessionID];
vIsG2001Existed = this.m_SessionInfoList[pSessionID].IsG2001Login;
vInfo.SetG2001Login(pIsLogin);
if (!pIsLogin)
{
this.m_SessionInfoList.Remove(pSessionID);
}
}
if (!pIsLogin)
{
if (vIsG2001Existed && pSession != null)
{
this.WriteSessionDataToFile(pSessionID, GetSessionData(pSession));
}
}
}
}
/// <summary>
/// Session.IsNewSessionの場合のみこのメソッドを処理する
/// </summary>
/// <param name="pSessionID"></param>
public void AddSession(string pSessionID)
{
_log.Info("新なセッションを開始します。SessionID=" + pSessionID);
SessionInfo vInfo = new SessionInfo(pSessionID);
string vFileName = GetSessionFilePath(pSessionID);
if (!string.IsNullOrEmpty(vFileName))
{
ReadSessionDataFromFile(vFileName);
//セッションファイルが存在する場合、必ずG2001画面が開いた。
vInfo.SetG2001Login(true);
}
this.m_SessionInfoList.Add(pSessionID, vInfo);
}
private SessionStateItemCollection GetSessionData(HttpSessionState pSession)
{
if (pSession == null)
{
return null;
}
//Type vModule = pModule.GetType();
//FieldInfo vSessionDataField = vModule.GetField("_rqItem", BindingFlags.NonPublic | BindingFlags.Instance);
//SessionStateStoreData vData = (SessionStateStoreData)vSessionDataField.GetValue(pModule);
//if (vData == null)
//{
// return null;
//}
SessionStateItemCollection vData = new SessionStateItemCollection();
foreach (string key in pSession.Keys)
{
vData[key] = pSession[key];
}
return vData;
}
private string GetSessionFilePath(string pSessionID)
{
if (!Directory.Exists(this.m_SessionDataSavePath))
{
return "";
}
string[] vFiles = Directory.GetFiles(this.m_SessionDataSavePath, string.Format("{0}.data", pSessionID));
if (vFiles.Length == 0)
{
return "";
}
return vFiles[0];
}
private void WriteSessionDataToFile(string pSessionID, SessionStateItemCollection pList)
{
if (pList == null)
{
return;
}
string vFileName = GetSessionFilePath(pSessionID);
if (vFileName != "")
{
File.Delete(vFileName);
}
if (!Directory.Exists(this.m_SessionDataSavePath))
{
return;
}
try
{
vFileName = string.Format("{0}{1}{2}.data", this.m_SessionDataSavePath, this.m_SessionDataSavePath.EndsWith(@"\") ? "" : @"\", pSessionID);
FileStream vStream = new FileStream(vFileName, FileMode.Create, FileAccess.Write);
BinaryWriter vWriter = new BinaryWriter(vStream);
pList.Serialize(vWriter);
vWriter.Close();
vStream.Close();
vStream.Dispose();
_log.Info("セッションデータをサーバのディスクへ保存する。SessionID=" + pSessionID);
}
catch (Exception ex)
{
this._log.Error("セッションのデータをサーバのディスクに保存する時、エラーを発生しました。", ex);
}
}
private void ReadSessionDataFromFile(string pFileName)
{
if (!File.Exists(pFileName))
{
return;
}
SessionStateItemCollection vList = null;
try
{
FileStream vStream = new FileStream(pFileName, FileMode.Open, FileAccess.Read);
BinaryReader vReader = new BinaryReader(vStream);
vList = SessionStateItemCollection.Deserialize(vReader);
vReader.Close();
vStream.Close();
vStream.Dispose();
//データ読み取ると、ディスクから削除する
File.Delete(pFileName);
}
catch(Exception ex)
{
this._log.Error("サーバのディスクからセッションデータを読み取る時、エラーを発生しました。", ex);
}
if (vList != null)
{
try
{
HttpSessionState vSession = HttpContext.Current.Session;
_log.Info("セッションデータをサーバのディスクから読み込む。SessionID=" + vSession.SessionID);
foreach (string key in vList.Keys)
{
vSession[key] = vList[key];
}
}
catch (Exception ex)
{
this._log.Error("サーバのディスクからのセッションデータをセッションにセットする時、エラーを発生しました。", ex);
}
}
}
}
public class SessionInfo
{
private string m_SessionID = null;
private DateTime? m_SessionStartTime;
private bool m_IsG2001Login = false;
public bool IsG2001Login
{
get
{
return this.m_IsG2001Login;
}
}
public SessionInfo(string pSessionID)
{
this.m_SessionStartTime = DateTime.Now;
this.m_SessionID = pSessionID;
}
private void CheckWhetherG2001Existed()
{
//G2001を閉じるの操作方法は六つかある
//①画面の閉じるボタンで閉じる
//②画面の×ボタンで閉じる
//③エラー発生する時、ApplicationManagement.UserLogoutを呼び出して、全て画面を閉じる
//④G2001の子画面がある場合、セッションをタイムアウトする時、Session_Endメソッドでクリアする
//⑤同一ユーザで一回以上登録でログアウトされた場合、FormBase.Page_Loadでクリアする
//⑥手動的にシステムのタスクマネージャで終了なら、Session_Endでクリアする
}
public void SetG2001Login(bool isLogin)
{
this.m_IsG2001Login = isLogin;
}
}
}