And here is updated code improvements: camelCase, Cookie Expiration, native HashSet.RemoveWhere(), added AddOrUpdate(), proper locking and less locks by reusing more code
Other changes are that Set() now uses same logic as Add(). Add(), Set() and AddOrUpdate() do all now have overloads for expiration, using defaultTimeToLive if no Timespan is provided.
using System;
using System.Collections.Generic;
using System.Linq;
namespace CookieRepository
{
class Program
{
static void Main(string[] args)
{
CookieRepository<bool>.Add("myid", "Authenticated", true);
// do something...
// Check cookie again.
if (CookieRepository<bool>.ValueEquals("myid", "Authenticated", true))
{
Console.WriteLine("Value was true, user is Authenticated.");
}
else
{
Console.WriteLine("Value was false, user is NOT Authenticated.");
}
// Update cookie.
CookieRepository<bool>.Set("myid", "Authenticated", false);
// do something...
// Lets do another check.
if (CookieRepository<bool>.ValueEquals("myid", "Authenticated", true))
{
Console.WriteLine("Value was true, user is Authenticated.");
}
else
{
Console.WriteLine("Value was false, user is NOT Authenticated.");
}
// Adding a cookie that expires in 5 seconds.
CookieRepository<string>.Add("myid", "ExpireTest", "Some value", new TimeSpan(0,0,0,5));
// Lets make sure that it exist.
string expireTestValue;
if (CookieRepository<string>.TryGetValue("myid", "ExpireTest", out expireTestValue))
{
Console.WriteLine("ExpireTest cookie exist, value: {0}", expireTestValue);
// Lets sleep for a bit till it should have expired.
Console.WriteLine("Sleeping so that cookie expires...");
System.Threading.Thread.Sleep(6000);
if (CookieRepository<string>.TryGetValue("myid", "ExpireTest", out expireTestValue))
{
Console.WriteLine("ExpireTest cookie exist and is still valid, value: {0}", expireTestValue);
}
else
{
Console.WriteLine("ExpireTest cookie does not exist or have expired.");
}
}
else
{
Console.WriteLine("ExpireTest cookie does not exist or have expired.");
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
public static class CookieRepository<T>
{
private static readonly HashSet<Cookie<T>> Cookies = new HashSet<Cookie<T>>();
private static readonly object CookieLock = new object();
public static TimeSpan DefaultTimeToLive = new TimeSpan(30, 0, 0);
/// <summary>
/// Adds cookie using default Time To Live, when you want to add a cookie and being sure that cookie by same key does not already exist.
/// </summary>
/// <param name="sessionId">Session Id of owner</param>
/// <param name="key">cookie known as</param>
/// <param name="value">value of the cookie</param>
/// <returns></returns>
public static bool Add(string sessionId, string key, T value)
{
return Add(sessionId, key, value, DefaultTimeToLive);
}
/// <summary>
/// Adds cookie, when you want to add a cookie and being sure that cookie by same key does not already exist.
/// </summary>
/// <param name="sessionId">Session Id of owner</param>
/// <param name="key">cookie known as</param>
/// <param name="value">value of the cookie</param>
/// <param name="ttl"></param>
/// <returns></returns>
public static bool Add(string sessionId, string key, T value, TimeSpan ttl)
{
var cookie = GetCookie(sessionId, key);
if (cookie != null && !cookie.Expired)
{
return false;
}
AddOrReplace(sessionId, key, value, ttl);
return true;
}
/// <summary>
/// Sets a cookie using Default Time To Live, when ensurance that cookie by key does already exist.
/// </summary>
/// <param name="sessionId">Session Id of owner</param>
/// <param name="key">cookie known as</param>
/// <param name="value">value of the cookie</param>
public static bool Set(string sessionId, string key, T value)
{
return Set(sessionId, key, value, DefaultTimeToLive);
}
/// <summary>
/// Sets a cookie, when ensurance that cookie by key does already exist.
/// </summary>
/// <param name="sessionId"></param>
/// <param name="key"></param>
/// <param name="value"></param>
/// <param name="ttl"></param>
/// <returns></returns>
public static bool Set(string sessionId, string key, T value, TimeSpan ttl)
{
if (GetCookie(sessionId, key) == null)
{
return false;
}
AddOrReplace(sessionId, key, value, ttl);
return true;
}
/// <summary>
/// Adds or Replaces cookie with using Default Time To Live, when ensurance that cookie by key already exist is of no importance.
/// </summary>
/// <param name="sessionId">Session Id of owner</param>
/// <param name="key">cookie known as</param>
/// <param name="value">value of the cookie</param>
public static void AddOrReplace(string sessionId, string key, T value)
{
AddOrReplace(sessionId, key, value, DefaultTimeToLive);
}
/// <summary>
/// Adds or Replaces cookie, when ensurance that cookie by key already exist is of no importance.
/// </summary>
/// <param name="sessionId">Session Id of owner</param>
/// <param name="key">cookie known as</param>
/// <param name="value">value of the cookie</param>
/// <param name="ttl">When cookie will expire</param>
public static void AddOrReplace(string sessionId, string key, T value, TimeSpan ttl)
{
lock (CookieLock)
{
var cookie = GetCookie(sessionId, key);
if (cookie != null)
{
Cookies.Remove(cookie);
}
Cookies.Add(new Cookie<T>(sessionId, key, value, ttl));
}
}
/// <summary>
/// Removes cookie by specific key.
/// </summary>
/// <param name="sessionId">Session Id of owner</param>
/// <param name="key">cookie known as</param>
public static void Remove(string sessionId, string key)
{
lock (CookieLock)
{
var cookie = GetCookie(sessionId, key);
if (cookie != null)
{
Cookies.Remove(cookie);
}
}
}
/// <summary>
/// Removes all Cookies for a specific Session. (On disconnect)
/// </summary>
/// <param name="sessionId">Session Id of owner</param>
public static void RemoveAll(string sessionId)
{
lock (CookieLock)
{
Cookies.RemoveWhere(x => x.SessionId == sessionId);
}
}
/// <summary>
/// Returns ALL Cookies that exist in cache by key
/// </summary>
/// <param name="key">cookie known as</param>
/// <returns>Queryable Interface</returns>
public static IEnumerable<Cookie<T>> GetAll(string key)
{
lock (CookieLock)
{
return Cookies.Where(x => x.Key == key);
}
}
/// <summary>
/// Tries to get value from an cookie by Owner and key
/// </summary>
/// <param name="sessionId"></param>
/// <param name="key">cookie known as</param>
/// <param name="value">Out cookie</param>
/// <returns>Whether any cookie value could be found</returns>
public static bool TryGetValue(string sessionId, string key, out T value)
{
value = GetValue(sessionId, key);
return value != null;
}
/// <summary>
/// Returns cookie value by Owner and key
/// </summary>
/// <param name="sessionId">Session Id of owner</param>
/// <param name="key">cookie known as</param>
/// <returns>cookie value</returns>
private static T GetValue(string sessionId, string key)
{
lock (CookieLock)
{
return
Cookies.Where(x => x.SessionId == sessionId && x.Key == key && !x.Expired).Select(x => x.Value).FirstOrDefault();
}
}
/// <summary>
/// Tries to get cookie by Owner and key
/// </summary>
/// <param name="sessionId">Session Id of owner</param>
/// <param name="key">cookie known as</param>
/// <param name="cookie">Out cookie</param>
/// <returns>Whether any cookie could could be found</returns>
public static bool TryGetCookie(string sessionId, string key, out Cookie<T> cookie)
{
cookie = GetCookie(sessionId, key);
return cookie != null;
}
/// <summary>
/// Returns cookie by Owner and key
/// </summary>
/// <param name="sessionId">Session Id of owner</param>
/// <param name="key">cookie known as</param>
/// <returns>cookie Object</returns>
private static Cookie<T> GetCookie(string sessionId, string key)
{
lock (CookieLock)
{
return Cookies.FirstOrDefault(x => x.SessionId == sessionId && x.Key == key && !x.Expired);
}
}
/// <summary>
/// Tries to find cookie value and Compare it with our matchwith value.
/// </summary>
/// <param name="sessionId">Session Id of owner</param>
/// <param name="key">cookie known as</param>
/// <param name="matchwith">value to compare with</param>
/// <returns>Wheter cookie exsist and value matches with input value</returns>
public static bool ValueEquals(string sessionId, string key, T matchwith)
{
return GetValue(sessionId, key).Equals(matchwith);
}
}
public class Cookie<T> : IEquatable<string>
{
public Cookie(string sid, string key, T value, TimeSpan ttl)
{
SessionId = sid;
Value = value;
Key = key;
Created = DateTime.UtcNow;
TimeToLive = ttl;
}
public string SessionId { get; private set; }
public string Key { get; private set; }
public T Value { get; private set; }
public DateTime Created { get; private set; }
public TimeSpan TimeToLive { get; private set; }
public bool Expired
{
get { return DateTime.UtcNow > Expires; }
}
public DateTime Expires
{
get { return Created + TimeToLive; }
}
public bool Equals(string other)
{
return string.Format("{0}-{1}", SessionId, Key).Equals(other);
}
public override bool Equals(object other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
if (!(other is Cookie<T>)) return false;
return Equals((T)other);
}
public override string ToString()
{
return string.Format("{0}-{1}", SessionId, Key);
}
public override int GetHashCode()
{
var hash = 13;
hash = (hash * 7) + SessionId.GetHashCode();
hash = (hash * 7) + Key.GetHashCode();
return hash;
}
}
}