从另一个线程访问会话数据

mna*_*ito 13 .net c# asp.net

我有一个问题.在我的网络应用程序中,我有一个页面,启动另一个线程,耗时的任务.在这个新线程中,我调用了一个我的架构方法(在另一个项目中 - 一个架构项目).问题是:在其中一种方法中,我访问了一个HttpContext.Current.Session字段.但是当我启动应用程序时,会抛出一个异常,说该对象(HttpContext.Current.Session)有一个空引用.我怎么能设置新线程的上下文与HttpApplication上下文相同才能访问HttpContext.Current.Session

cas*_*One 9

这里有很多事情需要考虑.

如果你的线程的生命周期与页面的生命周期相等,并且你需要对它进行大量的随机访问HttpSessionState,那么你应该SynchronizationContext从使用static Current属性创建后台线程的调用中获取.

一旦你的,你可以传递给你的线程,然后当你需要访问任何HttpContextBase与请求相关联(这包括会话),你可以调用Post方法SynchronizationContext您传递给你的线程得到的值是(或设置它们):

// From thread servicing request.
var sc = SynchronizationContext.Current;

// Run the task
Task t = Task.Run(() => {
    // Do other stuff.
    // ...

    // The value to get from the session.
    string sessionValue = null;

    // Need to get something from the session?
    sc.Post(() => {
        // Get the value.
        sessionValue = HttpContext.Current.Session["sessionValue"];
    }

    // Do other stuff.
    // ...
});
Run Code Online (Sandbox Code Playgroud)

这样做很重要,因为对HttpContextBase(和与之相关的任何东西)的访问不是线程安全的,并且与处理请求的线程(井,上下文)相关联.

请注意,该Post方法不会阻塞,因此调用之后的代码Post(即后面的行// Do other stuff.)应该独立于传递给的委托Post.如果后面的代码是相关的,你需要在继续之前等待调用完成,那么你可以调用该Send方法 ; 它具有相同的签名,并将阻塞,直到委托中的代码被执行.

也就是说,如果您只想对值进行只读访问,那么最好调用代码之前获取它们,然后在后台线程中访问它们:

// Get the values needed in the background thread here.
var values = {
    SessionValue = HttpContext.Current.Session["sessionValue"];
};

// Run the task
Task t = Task.Run(() => {
    // Do other stuff.
    // ...

    // Work with the session value.
    if (values.SessionValue == ...)

    // Do other stuff.
    // ...
});
Run Code Online (Sandbox Code Playgroud)

如果您的线程在服务请求后将继续处理,那么您只有只读状态,并且必须在启动线程之前捕获它.一旦请求得到服务,即使会话存在,这也是一个合乎逻辑的概念; 根据会话状态的提供者(会话状态管理器,SQL Server等),每次有新请求进入时,对象都可以被水合.

您还必须处理会话超时问题,您不知道会话是否存在于您想要访问它的位置.