我这里有个问题。在我的网络应用程序中,我有一个页面启动另一个线程来完成耗时的任务。在这个新线程中,我调用了我的一种架构方法(在另一个项目中 - 一个架构项目)。问题是:在其中一种方法中,我访问了 HttpContext.Current.Session 字段。但是,当我启动应用程序时,会抛出一个异常,提示此对象 (HttpContext.Current.Session) 具有空引用。我如何将新线程的上下文设置为与 HttpApplication 上下文相同以便访问 HttpContext.Current.Session ?
最佳答案
这里有很多事情需要考虑。
如果您的线程的生命周期与页面的生命周期相同,并且您需要大量随机访问 HttpSessionState
, 那么你应该得到 SynchronizationContext
来自使用静态 Current
property 创建后台线程的调用.
一旦你有了它,你就可以把它传递给你的线程,然后当你需要访问 HttpContextBase
上的任何东西时与请求相关联(这包括 session ),您可以调用 Post
method在您传递给线程以获取值(或设置它们)的 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.
// ...
});
这样做很重要,因为访问 HttpContextBase
(以及与之关联的任何内容)不是线程安全的,并且与线程相关(好吧,上下文)处理请求。
请注意,Post
方法不会阻塞,因此调用 Post
之后的代码(即 //之后的行会执行其他操作。
) 应该独立于传递给 Post
的委托(delegate)。如果后面的代码是依赖的,你需要等待调用完成才能继续,那么你可以调用 Send
method ;它具有相同的签名,并且会阻塞直到委托(delegate)中的代码被执行。
就是说,如果您只想只读访问这些值,那么最好在调用您的代码之前获取它们,然后在您的代码中访问它们后台线程:
// 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.
// ...
});
如果您的线程将在请求得到服务后继续处理,那么您仅具有只读状态,并且您必须在开始之前捕获它线程。一旦请求得到服务,即使 session 存在,这也是一个合乎逻辑的概念;根据 session 状态的提供者( session 状态管理器、SQL Server 等),每次有新请求进入时,对象都可以被水化。
您还必须处理 session 超时问题,您甚至不知道 session 是否在您要访问它时存在。
关于c# - 从另一个线程访问 session 数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13036928/