您的位置:首页 > 数据库 > Redis

Redis提供商配置ASP.NET会话状态

2016-03-16 17:37 736 查看
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections.Specialized;
using System.Web.SessionState;
using ServiceStack.Redis;
using System.Configuration;
using System.Configuration.Provider;
using System.Web.Configuration;
using System.IO;

namespace RedisProvider.SessionProvider
{

#region Session Item Model
public class SessionItem
{

#region Properties
public DateTime CreatedAt { get; set; }
public DateTime LockDate { get; set; }
public int LockID { get; set; }
public int Timeout { get; set; }
public bool Locked { get; set; }
public string SessionItems { get; set; }
public int Flags { get; set; }
#endregion Properties

}
#endregion Session Item Model

public class CustomServiceProvider : System.Web.SessionState.SessionStateStoreProviderBase, IDisposable
{

#region Properties
private string ApplicationName
{
get
{
if (ConfigurationManager.AppSettings.AllKeys.Contains("Application.Name"))
{
return ConfigurationManager.AppSettings["Application.Name"];
}

return string.Empty;
}
}

private RedisClient RedisSessionClient
{
get
{

if (!string.IsNullOrEmpty(this.redisPassword))
{
return new RedisClient(this.redisServer, this.redisPort, this.redisPassword);
}

return new RedisClient(this.redisServer, this.redisPort);
}
}

private string redisServer = "localhost";
private int redisPort = 6379;
private string redisPassword = string.Empty;
private SessionStateSection sessionStateConfig = null;
private bool writeExceptionsToLog = false;
#endregion Properties

#region Private Methods
/// <summary>
/// Prepends the application name to the redis key if one exists. Querying by application name is recommended for session
/// </summary>
/// <param name="id">The session id</param>
/// <returns>Concatenated string applicationname:sessionkey</returns>
private string RedisKey(string id)
{
return string.Format("{0}{1}", !string.IsNullOrEmpty(this.ApplicationName) ? this.ApplicationName + ":" : "", id);
}
#endregion Private Methods

#region Constructor
public CustomServiceProvider()
{

}
#endregion Constructor

#region Overrides
public override void Dispose()
{

}

public override void Initialize(string name, NameValueCollection config)
{

// Initialize values from web.config.
if (config == null)
{
throw new ArgumentNullException("config");
}

if (name == null || name.Length == 0)
{
name = "RedisSessionStateStore";
}

if (String.IsNullOrEmpty(config["description"]))
{
config.Remove("description");
config.Add("description", "Redis Session State Provider");
}

// Initialize the abstract base class.
base.Initialize(name, config);

// Get <sessionState> configuration element.
Configuration cfg = WebConfigurationManager.OpenWebConfiguration(ApplicationName);
sessionStateConfig = (SessionStateSection)cfg.GetSection("system.web/sessionState");

if (config["writeExceptionsToEventLog"] != null)
{
if (config["writeExceptionsToEventLog"].ToUpper() == "TRUE")
this.writeExceptionsToLog = true;
}

if (config["server"] != null)
{
this.redisServer = config["server"];
}

if (config["port"] != null)
{
int.TryParse(config["port"], out this.redisPort);
}

if (config["password"] != null)
{
this.redisPassword = config["password"];
}
}

public override bool SetItemExpireCallback(SessionStateItemExpireCallback expireCallback)
{
return true;
}

public override void SetAndReleaseItemExclusive(HttpContext context, string id, SessionStateStoreData item, object lockId, bool newItem)
{
using (RedisClient client = this.RedisSessionClient)
{
// Serialize the SessionStateItemCollection as a string.
string sessionItems = Serialize((SessionStateItemCollection)item.Items);

try
{
if (newItem)
{
SessionItem sessionItem = new SessionItem();
sessionItem.CreatedAt = DateTime.UtcNow;
sessionItem.LockDate = DateTime.UtcNow;
sessionItem.LockID = 0;
sessionItem.Timeout = item.Timeout;
sessionItem.Locked = false;
sessionItem.SessionItems = sessionItems;
sessionItem.Flags = 0;

client.Set<SessionItem>(this.RedisKey(id), sessionItem, DateTime.UtcNow.AddMinutes(item.Timeout));
}
else
{
SessionItem currentSessionItem = client.Get<SessionItem>(this.RedisKey(id));
if (currentSessionItem != null && currentSessionItem.LockID == (int?)lockId)
{
currentSessionItem.Locked = false;
currentSessionItem.SessionItems = sessionItems;
client.Set<SessionItem>(this.RedisKey(id), currentSessionItem, DateTime.UtcNow.AddMinutes(item.Timeout));
}
}
}
catch (Exception e)
{
throw e;
}
}
}

public override SessionStateStoreData GetItemExclusive(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actions)
{
return GetSessionStoreItem(true, context, id, out locked, out lockAge, out lockId, out actions);
}

public override SessionStateStoreData GetItem(HttpContext context, string id, out bool locked, out TimeSpan lockAge, out object lockId, out SessionStateActions actionFlags)
{
return GetSessionStoreItem(false, context, id, out locked, out lockAge, out lockId, out actionFlags);
}

private SessionStateStoreData GetSessionStoreItem(bool lockRecord,
HttpContext context,
string id,
out bool locked,
out TimeSpan lockAge,
out object lockId,
out SessionStateActions actionFlags)
{

// Initial values for return value and out parameters.
SessionStateStoreData item = null;
lockAge = TimeSpan.Zero;
lockId = null;
locked = false;
actionFlags = 0;

// String to hold serialized SessionStateItemCollection.
string serializedItems = "";

// Timeout value from the data store.
int timeout = 0;

using (RedisClient client = this.RedisSessionClient)
{
try
{
if (lockRecord)
{
locked = false;
SessionItem currentItem = client.Get<SessionItem>(this.RedisKey(id));

if (currentItem != null)
{
// If the item is locked then do not attempt to update it
if (!currentItem.Locked)
{
currentItem.Locked = true;
currentItem.LockDate = DateTime.UtcNow;
client.Set<SessionItem>(this.RedisKey(id), currentItem, DateTime.UtcNow.AddMinutes(sessionStateConfig.Timeout.TotalMinutes));
}
else
{
locked = true;
}
}
}

SessionItem currentSessionItem = client.Get<SessionItem>(this.RedisKey(id));

if (currentSessionItem != null)
{
serializedItems = currentSessionItem.SessionItems;
lockId = currentSessionItem.LockID;
lockAge = DateTime.UtcNow.Subtract(currentSessionItem.LockDate);
actionFlags = (SessionStateActions)currentSessionItem.Flags;
timeout = currentSessionItem.Timeout;
}
else
{
locked = false;
}

if (currentSessionItem != null && !locked)
{
// Delete the old item before inserting the new one
client.Remove(this.RedisKey(id));

lockId = (int?)lockId + 1;
currentSessionItem.LockID = lockId != null ? (int)lockId : 0;
currentSessionItem.Flags = 0;

client.Set<SessionItem>(this.RedisKey(id), currentSessionItem, DateTime.UtcNow.AddMinutes(sessionStateConfig.Timeout.TotalMinutes));

// If the actionFlags parameter is not InitializeItem,
// deserialize the stored SessionStateItemCollection.
if (actionFlags == SessionStateActions.InitializeItem)
{
item = CreateNewStoreData(context, 30);
}
else
{
item = Deserialize(context, serializedItems, timeout);
}
}
}

catch (Exception e)
{
throw e;
}
}

return item;
}

public override void ReleaseItemExclusive(HttpContext context, string id, object lockId)
{

using (RedisClient client = this.RedisSessionClient)
{
SessionItem currentSessionItem = client.Get<SessionItem>(this.RedisKey(id));

if (currentSessionItem != null && (int?)lockId == currentSessionItem.LockID)
{
currentSessionItem.Locked = false;
client.Set<SessionItem>(this.RedisKey(id), currentSessionItem, DateTime.UtcNow.AddMinutes(sessionStateConfig.Timeout.TotalMinutes));
}
}
}

public override void RemoveItem(HttpContext context, string id, object lockId, SessionStateStoreData item)
{
using (RedisClient client = this.RedisSessionClient)
{
// Delete the old item before inserting the new one
client.Remove(this.RedisKey(id));
}
}

public override void CreateUninitializedItem(HttpContext context, string id, int timeout)
{
using (RedisClient client = this.RedisSessionClient)
{
SessionItem sessionItem = new SessionItem();
sessionItem.CreatedAt = DateTime.Now.ToUniversalTime();
sessionItem.LockDate = DateTime.Now.ToUniversalTime();
sessionItem.LockID = 0;
sessionItem.Timeout = timeout;
sessionItem.Locked = false;
sessionItem.SessionItems = string.Empty;
sessionItem.Flags = 0;

client.Set<SessionItem>(this.RedisKey(id), sessionItem, DateTime.UtcNow.AddMinutes(timeout));
}
}

public override SessionStateStoreData CreateNewStoreData(System.Web.HttpContext context, int timeout)
{
return new SessionStateStoreData(new SessionStateItemCollection(),
SessionStateUtility.GetSessionStaticObjects(context),
timeout);
}

public override void ResetItemTimeout(HttpContext context, string id)
{

using (RedisClient client = this.RedisSessionClient)
{
try
{
// TODO :: GET THIS VALUE FROM THE CONFIG
client.ExpireEntryAt(id, DateTime.UtcNow.AddMinutes(sessionStateConfig.Timeout.TotalMinutes));
}
catch (Exception e)
{
throw e;
}
}
}

public override void InitializeRequest(HttpContext context)
{
// Was going to open the redis connection here but sometimes I had 5 connections open at one time which was strange
}

public override void EndRequest(HttpContext context)
{
this.Dispose();
}
#endregion Overrides

#region Serialization
/// <summary>
/// Serialize is called by the SetAndReleaseItemExclusive method to
/// convert the SessionStateItemCollection into a Base64 string to
/// be stored in MongoDB.
/// </summary>
private string Serialize(SessionStateItemCollection items)
{
using (MemoryStream ms = new MemoryStream())
using (BinaryWriter writer = new BinaryWriter(ms))
{
if (items != null)
items.Serialize(writer);

writer.Close();

return Convert.ToBase64String(ms.ToArray());
}
}

private SessionStateStoreData Deserialize(HttpContext context, string serializedItems, int timeout)
{
using (MemoryStream ms = new MemoryStream(Convert.FromBase64String(serializedItems)))
{
SessionStateItemCollection sessionItems = new SessionStateItemCollection();

if (ms.Length > 0)
{
using (BinaryReader reader = new BinaryReader(ms))
{
sessionItems = SessionStateItemCollection.Deserialize(reader);
}
}

return new SessionStateStoreData(sessionItems,
SessionStateUtility.GetSessionStaticObjects(context),
timeout);
}
}
#endregion Serialization
}
}


<system.web
<sessionState timeout="1" mode="Custom" customProvider="RedisSessionStateProvider" cookieless="false">
<providers>
<add name="RedisSessionStateProvider" writeexceptionstoeventlog="false" type="RedisProvider.SessionProvider.CustomServiceProvider" server="192.168.1.118" port="6379" password="admin"></add>
</providers>
</sessionState>
</system.web>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: