Some years ago I remember I spent quite some time while trying to debug a cross session contamination of data.
The problem ended up being due to an improper use of the
static modifier in the context of ASP.NET applications.
In fact, in ASP.NET,
static objects are instantiated one time for each application domain, and all processing in the application share the same object, while at that time I understood that the
static modifier acted within the page life span!
For this very reason, a Singleton pattern that relies on a
static object will be most of the times useless if the wished behaviour is to have its life span limited to the page life cycle: a
static object is always shared across the entire application!
In my own experience, when I require a single instance of an object I most often want its scope and life cycle to be within a web request or single session and in very few occasions to be application wide.
I decided I was going to create a helper class that would allow me to instantiate a Singleton instance of an object and being able to decide its scope.
I put together a
Singleton helper class and 3
persister classes: one for the
Session, one for the
Page life cycle and one for the
Application.
The persister classes would define the singleton life span and scope so that if I wanted to have a single instance of
MyObjectClass with a life span of a single web request I could easily get an instance of it in the following way:
MyObjectClass o = Singleton<MyObjectClass, ItemsPersister>.GetInstance();
Likewise within the session life span:
MyObjectClass o = Singleton<MyObjectClass, SessionPersister>.GetInstance();
And application life span:
MyObjectClass o = Singleton<MyObjectClass, ApplicationPersister>.GetInstance();
The Singleton<T, S> has T which is the type of the class I want to have a single instance of, and S the type of the Persister that I wish to adopt.
Here is the singleton helper and the persisters full code:
public class Singleton<T, S> : ISingleton
where T : new()
where S : IPersister, new()
{
public static T GetInstance()
{
var identifier = new T().GetType().Name;
var persister = new S();
var instance = (T)persister.Get(identifier);
if (instance == null)
{
instance = new T();
persister.Set(identifier, instance);
}
return (T)instance;
}
}
public interface IPersister
{
object Get(string name);
void Set(string name, object o);
void Remove(string name);
}
public class SessionPersister : IPersister
{
private HttpContext _Context;
public SessionPersister()
{
this._Context = HttpContext.Current;
}
public object Get(string name)
{
return this._Context.Session[name];
}
public void Set(string name, object o)
{
this._Context.Session.Add(name, o);
}
public void Remove(string name)
{
this._Context.Session.Remove(name);
}
}
public class ItemsPersister : IPersister
{
private HttpContext _Context;
public ItemsPersister()
{
this._Context = HttpContext.Current;
}
public object Get(string name)
{
return this._Context.Items[name];
}
public void Set(string name, object o)
{
this._Context.Items.Add(name, o);
}
public void Remove(string name)
{
this._Context.Items.Remove(name);
}
}
public class ApplicationPersister : IPersister
{
private HttpContext _Context;
public ApplicationPersister()
{
this._Context = HttpContext.Current;
}
public object Get(string name)
{
return this._Context.Application[name];
}
public void Set(string name, object o)
{
this._Context.Application.Add(name, o);
}
public void Remove(string name)
{
this._Context.Application.Remove(name);
}
}