【发布时间】:2014-04-27 04:30:03
【问题描述】:
对不起标题。这是相当复杂的。我会尽量用一种简化、抽象的方式来概括它。
在 Web 表单应用程序中,将在两种不同的上下文中使用 DAL:
- 来自代码隐藏
- 来自 Web API 控制器
在每次调用中,DAL 都需要知道当前的用户 ID,以便它可以针对数据库事务存储此 ID。我在 DAL 中添加了一个 Func 类型的静态属性,这样当使用 DAL 时,可以为它提供一个方法(通过 callng 代码),允许它获取用户 ID。
从代码隐藏进行的调用将提供从会话中获取用户 ID 的 GetUserId 方法,而 Web API 控制器调用(无状态)将用户 ID 作为参数并能够返回该值.
我担心的是,Web 环境中的静态数据是跨会话共享的。所以..
- 当用户 A 运行设置 GetUserId 方法以返回 Session["UserId"] 的会话,而用户 B 运行同时执行相同操作的会话时,每个事务是否会收到正确的用户 ID?我在想,因为 HttpContext.Current 本身就是静态的,所以应该没问题。
- 当用户A通过Web API控制器调用并设置GetUserId方法返回参数值(假设id为1),然后用户B同时进行同样的调用,但用户id参数为2... 一个会取代另一个,还是会保持不同?我想他们可能会发生冲突。
如果他们会发生冲突,那么我会找到另一种方法来做到这一点,但我想避免将用户 ID 传递给每个对象 Save()。
解决方案
在 Steven 的回答的提示下,我玩了 CallContext 只是为了向自己证明它会针对特定线程保留上下文,尽管是通过静态调用。下面是一个非常简单的重叠线程测试。接下来我在Web API环境下试试,应该是一样的。
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");
}
}
【问题讨论】:
-
我认为您应该完全回避这个问题,并将一个值传递给您的 DAL 构造函数或方法调用。我明白你想要达到的目标,我只是认为这不值得。
-
顺便说一句:HttpContext.Current 由
Global.asax填充每个请求,会话也是如此。
标签: c# asp.net session data-access-layer