Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么我的ASP.Net静态函数';s";上下文“;用户会话之间的交叉?_Asp.net_Static Methods - Fatal编程技术网

为什么我的ASP.Net静态函数';s";上下文“;用户会话之间的交叉?

为什么我的ASP.Net静态函数';s";上下文“;用户会话之间的交叉?,asp.net,static-methods,Asp.net,Static Methods,我想我需要一些帮助来理解ASP.Net应用程序中静态对象是如何持久存在的。我有这样一个场景: 类库中的someFile.cs: public delegate void CustomFunction(); public static class A { public static CustomFunction Func = null; } public class Q { public Q() { if (A.Func != null) {

我想我需要一些帮助来理解ASP.Net应用程序中静态对象是如何持久存在的。我有这样一个场景:

类库中的someFile.cs:

public delegate void CustomFunction();

public static class A {
    public static CustomFunction Func = null;
}
public class Q {
    public Q() {
        if (A.Func != null) {
            A.Func();
        }
    }
}
类库中的someOtherFile.cs:

public delegate void CustomFunction();

public static class A {
    public static CustomFunction Func = null;
}
public class Q {
    public Q() {
        if (A.Func != null) {
            A.Func();
        }
    }
}
某些ASP.Net页面:

Page_Init {
    A.Func = MyFunc;
}

public void MyFunc() {
    System.IO.File.AppendAllText(
        "mydebug.txt", DateTime.Now.ToString("hh/mm/ss.fff", Session.SessionID));
}

Page_Load {
    Q myQ = new Q();
    System.Threading.Thread.Sleep(20000);
    mQ = new Q();
}
我的想法是,我有一个业务对象,它基于UI级别的回调函数执行一些操作。我在Page_Init上将回调函数设置为一个静态变量(在真正的代码版本中,在母版页中,如果这有区别的话)。我认为页面的每一次执行,不管它来自哪个用户会话,都会经过该函数的逻辑,但会对自己的数据集进行操作。相反,似乎正在发生的是并发问题

如果我运行一个用户会话,那么当它在调用回调函数之间休眠时,启动另一个用户会话,当第一个会话从休眠状态返回时,它将从第二个用户会话获取会话ID。这怎么可能呢

mydebug.txt的输出:

01/01/01.000 abababababab  (session #1, first call)
01/01/05.000 cdcdcdcdcdcd  (session #2, first call - started 5 seconds after session #1)
01/01/21.000 cdcdcdcdcdcd  (session #1 returns after the wait but has assumed the function context from session #2!!!!!)
01/01/25.000 cdcdcdcdcdcd  (session #2 returns with its own context)

为什么函数的上下文(意思是它的本地数据等)会从一个用户会话覆盖到另一个用户会话?

对asp.net站点的每个请求都会进入并在它自己的线程上处理。但是这些线程中的每一个都属于同一个应用程序。这意味着您标记为静态的任何内容都将在所有请求中共享,因此也将在所有会话和用户中共享


在这种情况下,作为page类一部分的
MyFunc
函数会在
A
中的静态
Func
成员上复制到每个页面,因此每次用户进行页面初始化时,他都会替换所有请求使用的
A.Func

静态数据在整个webapp中共享。
简而言之,它是在Web应用程序中请求服务的所有线程之间共享的,它不是以任何方式绑定到会话/线程/用户,而是作为WebApp作为一个整体。(不像PHP,每个请求都存在于它自己的隔离环境栏中,提供了几个旋钮——例如会话变量)。

< P>您可以考虑使用一个解决方案[线程静态]。


它将使您的静态每个线程。但是,有一些警告,所以您应该进行测试。

我不会试图改进其他答案对静态成员的解释,但我想指出另一种解决当前问题的方法

作为一种解决方案,您可以制作类
a
的面向实例版本,将其存储在页面级变量中,并在页面加载时将其传递给
Q
的构造函数:

public class MyPage: Page {
    private A2 _a2;

    // I've modified A2's constructor here to accept the function
    protected Page_Init() { this._a2 = new A2(MyFunc); }

    protected Page_Load() { 
        Q myQ = new Q(this._a2); 
        // etc..
    }
}
事实上,如果不需要提前声明
A2
,您可以在
Page\u Load
中创建
Q
的实例时实例化它


编辑:要回答您在其他评论中提出的问题,共享变量的原因是请求共享同一个委托,该委托只有一个变量副本。有关更多详细信息,请参阅Jon Skeet的。

如果您希望数据仅用于当前请求,请使用
HttpContext。Items


如果希望当前用户会话的数据保持不变(假设已启用会话状态),请使用
HttpContext.session

我确实知道功能地址正在被替换。但是,我不明白为什么函数中访问的数据也会发生交叉。为什么具有session.SessionID=abababab的session#1在再次调用myFunc时突然具有session.SessionID=cdcdcd?因为在将当前会话对象分配给静态委托时,委托捕获该方法的整个环境,包括当前会话对象。因为在session#1调用静态A.Func()之前构造函数会话#2中的方法将该函数替换为它自己的实现。你在第二轮调用一个完全不同的函数。它是通过闭包来实现的。+1杰夫提到闭包时,灯为我发出咔哒声。感谢您的回答和评论。除了链接中有关初始值的MSDN注释外,还有哪些注意事项?这在ASP.NET中不起作用。您无法预测哪个线程将为给定的请求提供服务。ThreadStatic变量的另一种替代方法是HttpContext.Current.Items,它的作用域是一个不同的请求(例如,请参阅)。@Matt-通常,单个线程将为请求提供服务。ThreadStatic的问题是,在请求结束后,这些值将持续存在于该线程上。虽然这在您的场景中可能有效,但它不是您想要的。使用HttpContext.Items。请记住:在会话过程中,同一个用户可能会出现在许多不同的线程上。就像我试图在对Joel的评论中正确表述一样,我理解为什么在应用程序域中共享函数引用。我不明白为什么函数逻辑中的会话/线程/用户绑定变量也在应用程序域中共享。DOH!!!!!!!现在我完全明白了。我甚至没有意识到我已经在这个案子中设定了一个了结。我的示例代码是实际代码的一个极其简化的版本——不幸的是,您提出的解决方案不适合实际情况。但是非常感谢结束语的解释。谢谢大家的帮助。堆栈溢出规则。:)