My services(or services that depend on services) need to know about a current action group id. To add an extra optional parameter to each service for the id was an idea but in my current environment to difficult and ugly because every service would have to take in the parameter only to pass it to other services.
My solution was a class ActionGroupContext
which stores the current context in a static ThreadStore
or HttpStore
.
What I don't like especially with my solution is that even though you are not do web application you have to include a reference to System.Web, but the convenience is great, the user does not need any setup code.
Do you have any improvement ideas?
Demo usage:
public void SomeApplicationMehtod()
{
using (new ActionGroupContext())
{
someService.SomeMehtod();
}
}
public class SomeService
{
public void SomeMehtod()
{
var id = ActionGroupContext.Id;
//Do something with the Id.
}
}
The code:
public class ActionGroupContext : IDisposable
{
private static readonly GuidStore GuidStore = new GuidStore("Action-Group-Id-Store");
private readonly Guid? oldId;
public ActionGroupContext()
{
oldId = GuidStore.GetGuid();
GuidStore.SetGuid(Id ?? Guid.NewGuid());
}
public static Guid? Id
{
get { return GuidStore.GetGuid(); }
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
GuidStore.SetGuid(oldId);
}
}
}
public class ThreadStore : IStore
{
private readonly LocalDataStoreSlot slot;
public ThreadStore(string storeKey)
{
slot = Thread.GetNamedDataSlot(storeKey);
}
public object GetData()
{
return Thread.GetData(slot);
}
public void SetData(object data)
{
Thread.SetData(slot, data);
}
}
public interface IStore
{
object GetData();
void SetData(object data);
}
public class ThreadStore : IStore
{
private readonly LocalDataStoreSlot slot;
public ThreadStore(string storeKey)
{
slot = Thread.GetNamedDataSlot(storeKey);
}
public object GetData()
{
return Thread.GetData(slot);
}
public void SetData(object data)
{
Thread.SetData(slot, data);
}
}
public class HttpStore : IStore
{
private readonly string storeKey;
public HttpStore(string storeKey)
{
if (!IsContextForStoreAvailable())
{
throw new InvalidOperationException("HttpContext is not available");
}
this.storeKey = storeKey;
}
public object GetData()
{
return HttpContext.Current.Items(storeKey);
}
public void SetData(object data)
{
HttpContext.Current.Items(storeKey) = data;
}
public static bool IsContextForStoreAvailable()
{
return HttpContext.Current != null;
}
}