Мне нужно создать экземпляр объекта-одиночки для каждого веб-запроса, чтобы данные обрабатывались один раз и действовали на протяжении всего запроса. Я использовал HttpContext.Current.Items
для обмена данными во время HTTP-запроса, все было в порядке, пока нам не потребовался экземпляр объекта singleton в нескольких потоках, первое, что я придумал, - передать экземпляр HttpContext новому потоку:
HttpContext context = HttpContext.Current;
ThreadPool.QueueUserWorkItem(callback =>
{
HttpContext.Current = context;
// blah blah
});
Что я не считаю поточно-ориентированнымподход как отмеченный здесь .
Используя Reflector, я понял, что HttpContext.Current.Items фактически использует CallContext для хранения объектов в каждом логическом потоке.Поэтому я изменил одноэлементный интерфейс следующим образом:
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 выполняется в другом как , отмеченное здесь , но я не знаю как / почему?
update:
Мы сохраняемэкземпляр каждого онлайн-пользователя в массиве на сервере.Объект-одиночка на самом деле является ссылкой на объект, представляющий текущего пользователя.Текущий пользователь должен быть уникальным и доступным в каждом потоке для запросов к базе данных, ведения журнала, обработки ошибок и многого другого, вот как это делается:
public static ApplicationUser CurrentUser
{
get { return CallContext.GetData("ApplicationUser") as ApplicationUser ; }
set { CallContext.SetData("ApplicationUser", value); }
}