静态委托如何访问非静态,服务器端,基于会话的信息?

时间:2014-03-20 11:10:17

标签: c# asp.net session data-access-layer

对标题感到抱歉。这相当复杂。我将尝试以简化的抽象方式(尽我所能)总结它。

在Web表单应用程序中,DAL将在两个不同的上下文中使用:

  1. 来自代码隐藏
  2. 来自Web API控制器
  3. 在每次调用中,需要使DAL知道当前的用户ID,以便它可以将此id存储在数据库事务中。我已经为DAL添加了一个类型为Func的静态属性,这样当使用DAL时,可以为它提供一个允许它获取用户ID的方法(通过callng代码)。

    从代码隐藏进行的调用将提供一个GetUserId方法,该方法从会话中获取用户ID,而Web API控制器调用(无状态)将具有用户id作为参数,并且能够返回该值

    我担心的是,Web环境中的静态是跨会话共享的。所以..

    1. 当用户A运行会话以设置GetUserId方法以返回会话[" UserId"],并且用户B运行同时执行相同操作的会话时,每个事务将接收正确的用户ID?我认为因为HttpContext.Current本身就是静态的,所以应该没问题。
    2. 当用户A通过Web API控制器进行呼叫并设置GetUserId方法以返回参数值(让他们说id为1),然后用户B同时进行相同的呼叫,但是用户ID参数是2 ...一个会替换另一个,还是会保持不同?我认为他们可能会发生冲突。
    3. 如果他们发生冲突,那么我会找到另一种方法来做,但我想避免将用户ID传递给每个对象Save()。

      史蒂文的回答提示,我有一个游戏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");
          }
      }
      

1 个答案:

答案 0 :(得分:2)

HttpContext.Current.Session阅读显然是安全的,因为HttpContext.Current会为每个请求返回不同的HttpContext个实例。但由于您的Func字段是静态的,因此替换Func当然会使您的代码失败,因为每个App域只有一个静态字段实例。所以你应该采取不同的方法。

例如,不是替换Func,而是将其初始化一次,并让它处理Web API案例。例如:

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);
}