Sorry about the title. This is fairly complex. I'll try to summarise it in a simplified, abstract way (as much as I can).
In a web forms application, the DAL will be used from two different contexts:
In each call, the DAL needs to be made aware of the current User Id so that it can store this id against database transactions. I've added a static property to the DAL that is of type Func, such that when the DAL is used, it can be provided with a method (by the callng code) that allows it to fetch the user id.
The calls made from code-behind would provide a GetUserId method that get the user id from session, whereas the Web API controller calls (which are stateless) will have the user id as a parameter and will be able to return that value.
What concerns me is that statics in a web environment are shared across sessions. So..
If they're going to clash, then I'll find another way to do it, but I wanted to avoid having to pass the user id into every object Save().
SOLUTION
Prompted by Steven's answer, I've had a play CallContext just to prove to myself that it will retain context against a specific thread, in spite of being called through a static. Following is a very simple test with overlapping threads. Next I'll try it in a Web API environment, which should be the same.
class Program
{
static void Main(string[] args)
{
for (var i = 0; i < 10; i++)
StartTestThread(i);
Console.ReadKey();
}
private static void StartTestThread(int i)
{
Thread.Sleep(2000);
ThreadPool.QueueUserWorkItem(delegate {
Console.WriteLine(string.Format("[{0}] Setting context...", i));
SetCallContext(i);
Console.WriteLine(string.Format("[{0}] Waiting...", i));
Thread.Sleep(5000);
Console.WriteLine(string.Format("[{0}] Context is {1}", i, GetCallContext()));
});
}
private static void SetCallContext(int i)
{
CallContext.LogicalSetData("Test", i);
}
private static int GetCallContext()
{
return (int) CallContext.LogicalGetData("Test");
}
}
Reading from HttpContext.Current.Session
is obviously safe, since HttpContext.Current
returns a different HttpContext
instance for each request. But since your Func
field is static, replacing the Func
will of course make your code fail misserably, since there is just one instance of a static field per App Domain. So you should take a different approach.
For instance, instead of replacing the Func, initialize it just once and let it handle the Web API case as well. For instance:
GetUserId = () =>
{
var context = HttpContext.Current;
// MVC / Web Forms
if (context.Session != null && context.Session["UserId"] != null) {
return (int)context.Session["UserId"];
}
// Web API
return (int)CallContext.LogicalGetData("__userId");
};
public static void RegisterWebApiUserId(int userId) {
CallContext.LogicalSetData("__userId", userId);
}