using System;
using System.Collections.Specialized;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Web;
using System.Web.SessionState;
using Pfz.Threading;
namespace Pfz.Caching
{
/// <summary>
/// Class that provides session management features using CacheDictionary class.
/// </summary>
public sealed class PfzSessionStateStoreProvider:
SessionStateStoreProviderBase
{
private IPfzSessionStateStoreProvider fProvider;
private static string fSessionIdPrefix;
internal static string GetId(string id)
{
if (fSessionIdPrefix == null)
return id;
return fSessionIdPrefix + id;
}
/// <summary>
/// Connects to the SessionStateServer.
/// </summary>
public override void Initialize(string name, NameValueCollection config)
{
base.Initialize(name, config);
string host = config.Get("host");
int port = int.Parse(config.Get("port"));
fSessionIdPrefix = config.Get("group");
if (fSessionIdPrefix != null)
fSessionIdPrefix += ':';
string fullHost = string.Format("tcp://{0}:{1}/IPfzSessionStateStoreProvider", host, port);
fProvider = (IPfzSessionStateStoreProvider)Activator.GetObject(typeof(IPfzSessionStateStoreProvider), fullHost);
}
/// <summary>
/// Does nothing.
/// </summary>
public override void Dispose()
{
fProvider = null;
}
/// <summary>
/// Only initializes an empty dictionary.
/// </summary>
public override SessionStateStoreData CreateNewStoreData(HttpContext context, int timeout)
{
var items = new PfzSessionStateItemCollection();
var staticObjects = SessionStateUtility.GetSessionStaticObjects(context);
return new SessionStateStoreData(items, staticObjects, timeout);
}
/// <summary>
/// Does nothing.
/// </summary>
public override void CreateUninitializedItem(HttpContext context, string id, int timeout)
{
}
/// <summary>
/// Does nothing.
/// </summary>
public override void EndRequest(HttpContext context)
{
}
/// <summary>
/// Loads a session from disk. The values are then loaded from disk or memory.
/// </summary>
public override SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
{
actions = SessionStateActions.None;
TimeSpan timeout;
long longLockId;
byte[] bytes = fProvider.GetItem(GetId(id), out longLockId, out lockAge, out timeout);
locked = (longLockId != 0);
if (locked)
lockId = longLockId;
else
lockId = null;
if (bytes == null)
return null;
PfzSessionStateItemCollection dictionary = null;
BinaryFormatter binaryFormatter = new BinaryFormatter();
try
{
AbortSafe.Using
(
() => new MemoryStream(bytes),
(stream) => dictionary = (PfzSessionStateItemCollection)binaryFormatter.Deserialize(stream)
);
}
catch(SerializationException)
{
return null;
}
var staticObjects = SessionStateUtility.GetSessionStaticObjects(context);
return new SessionStateStoreData(dictionary, staticObjects, (int)timeout.TotalMinutes);
}
/// <summary>
/// Loads a session from disk and renames (locks) it. The values are then
/// loaded from disk or memory.
/// </summary>
public override SessionStateStoreData GetItemExclusive(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
{
actions = SessionStateActions.None;
TimeSpan timeout;
long longLockId;
byte[] bytes = fProvider.GetItemExclusive(GetId(id), out longLockId, out locked, out lockAge, out timeout);
if (longLockId == 0)
lockId = null;
else
lockId = longLockId;
if (bytes == null && lockId != null)
return null;
PfzSessionStateItemCollection dictionary = null;
if (bytes == null)
dictionary = new PfzSessionStateItemCollection();
else
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
try
{
AbortSafe.Using
(
() => new MemoryStream(bytes),
(stream) => dictionary = (PfzSessionStateItemCollection)binaryFormatter.Deserialize(stream)
);
}
catch(SerializationException)
{
return null;
}
}
var staticObjects = SessionStateUtility.GetSessionStaticObjects(context);
return new SessionStateStoreData(dictionary, staticObjects, (int)timeout.TotalMinutes);
}
/// <summary>
/// Does nothing.
/// </summary>
public override void InitializeRequest(HttpContext context)
{
}
/// <summary>
/// Only executed on exceptions.
/// </summary>
public override void ReleaseItemExclusive(HttpContext context, string id, object lockId)
{
long longLockId = 0;
if (lockId != null)
longLockId = (long)lockId;
fProvider.ReleaseItem(GetId(id), longLockId);
}
/// <summary>
/// Delete the file from disk.
/// </summary>
public override void RemoveItem(HttpContext context, string id, object lockId, SessionStateStoreData item)
{
fProvider.RemoveItem(GetId(id), (long)lockId);
}
/// <summary>
/// Does a keep alive to the session.
/// </summary>
/// <param name="context"></param>
/// <param name="id"></param>
public override void ResetItemTimeout(HttpContext context, string id)
{
fProvider.KeepAlive(GetId(id));
}
/// <summary>
/// Saves the session to the disk.
/// </summary>
public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData data, object lockId, bool newItem)
{
byte[] bytes = null;
BinaryFormatter binaryFormatter = new BinaryFormatter();
AbortSafe.Using
(
() => new MemoryStream(),
(stream) =>
{
binaryFormatter.Serialize(stream, data.Items);
bytes = stream.ToArray();
}
);
long longLockId = 0;
if (lockId != null)
longLockId = (long)lockId;
fProvider.SetAndReleaseItem(GetId(id), longLockId, bytes);
}
/// <summary>
/// Does nothing. The callback is not registered.
/// </summary>
public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback)
{
return false;
}
}
}