我需要为每个网络请求实例化一个单例对象,以便数据处理一次并在整个请求期间有效,我正在使用HttpContext.Current.Items
在 HTTP 请求期间共享数据,一切都很好,直到我们需要单例对象实例跨多个线程,我想到的第一件事是将 HttpContext 实例传递给新线程:
HttpContext context = HttpContext.Current;
ThreadPool.QueueUserWorkItem(callback =>
{
HttpContext.Current = context;
// blah blah
});
我认为这不是线程安全的方法此处注明 https://stackoverflow.com/questions/734821/using-an-httpcontext-across-threads.
使用 Reflector 我认为 HttpContext.Current.Items 实际上使用调用上下文在每个逻辑线程中存储对象。所以我将单例接口更改为:
public static SingletonType SingletonInstance
{
get { return CallContext.GetData(key) as SingletonType; }
set { CallContext.SetData(key, value); }
}
并且简单地覆盖SingletonInstance
当开始任何新线程时!该代码工作正常,但似乎在重负载下,CallContext.GetData(key) 返回 null 并且应用程序因空引用异常而崩溃!
我在想,如果CallContext.GetData
是原子的吗?但这似乎不对,CallContext 是线程特定的数据存储,并且必须是原子的,否则我就没有抓住要点!
我的另一个猜测是,设置 SingletonInstance (CallContext.SetData) 发生在一个线程中,而 CallContext.GetData 在另一个线程中执行此处注明 https://stackoverflow.com/a/736115/1041321但我不知道如何/为什么?
update:
我们将每个在线用户的实例保存在服务器上的数组中。单例对象实际上是对代表当前用户的对象的引用。当前用户必须是唯一的,并且在每个线程中都可以用于数据库查询、日志记录、错误处理等,具体操作如下:
public static ApplicationUser CurrentUser
{
get { return CallContext.GetData("ApplicationUser") as ApplicationUser ; }
set { CallContext.SetData("ApplicationUser", value); }
}