Класс HttpContext и его потокобезопасность

У меня есть объект Singleton в приложении со следующим свойством:

private AllocationActionsCollection AllocationActions
{
    get
    {
        return HttpContext.Current.Session["AllocationOptions.AllocationActions"] as AllocationActionsCollection;
    }
    set
    {
        HttpContext.Current.Session["AllocationOptions.AllocationActions"] = value;
    }
}

Я имею дело с одной ошибкой (HttpContext.Current.Session["AllocationOptions.AllocationActions"] имеет значение null, хотя предполагается, что для меня всегда установлено значение допустимого экземпляра...). Я только что прочитал в MSDN, что член экземпляра HttpContext не гарантирует потокобезопасность! Интересно, может ли это быть проблемой? Где-то в приложении может быть гонка за ресурсами, и момент, когда HttpContext.Current.Session["AllocationOptions.AllocationActions"] равен null, является моментом, когда установщик AllocationActions используется с помощью этого оператора:

AllocationActions = new AllocationActionsCollection(Instance.CacheId);

Мои вопросы:

а) Я шокирован тем, что HttpContext.Current.Session не является потокобезопасным. Как тогда безопасно использовать это свойство? б) есть ли у вас какие-либо идеи, почему эта переменная сеанса может быть нулевой (хотя я почти уверен, что устанавливаю ее до того, как она будет использована в первый раз)?

Спасибо, Павел

РЕДАКТИРОВАТЬ 1:

а) строка, которая инициализирует переменную сеанса, устанавливается каждые 2 минуты с помощью следующего оператора (выполняется в Page_Load)

AllocationActions = new AllocationActionsCollection(Instance.CacheId);

б) код, который вызывает геттер, вызывается в обработчиках событий (например, Button_Click)

c) в приложении нет пользовательских потоков. единственный общий обработчик HTTP


person dragonfly    schedule 27.09.2011    source источник
comment
Итак, что вызывает этот код? Является ли это явной ситуацией с потоками (вызов Thread.Start) или потоками является ли это веб-службой, обработчиком HTTP или чем-то еще?   -  person Brian Mains    schedule 27.09.2011
comment
Когда вы выполняете код, который возвращает нулевой сеанс? В конструкторе страниц Session IS null; В сеансе Page_Init или Page_Load НЕ НУЛЕВОЕ   -  person Emanuele Greco    schedule 27.09.2011
comment
вам нужно показать больше исходного кода - особенно. где это установлено, и уточните ситуацию с потоками... если, например, вы получаете доступ к HttpContext.Current вне потока IIS (т.е. в потоке, который вы начали отдельно), будучи размещенным в IIS, это даст интересные результаты...   -  person Yahia    schedule 27.09.2011
comment
Документы означают, что конкретный экземпляр HttpContext может безопасно использоваться только из одного потока за раз. Это желательное поведение, поскольку оно привязано к потоку, обрабатывающему запрос страницы.   -  person Nick Butler    schedule 27.09.2011


Ответы (4)


Объект singleton реализуется путем ограничения инстанцирования класса одним объектом.

HttpContext.Current.Session — это область, предназначенная для одного пользователя; любой объект, хранящийся в сеансе, будет доступен только для пользователя/сеанса, создавшего его.

Любой объект, хранящийся в Application, будет доступен только для каждого пользователя/сеанса.

Любой статический объект также будет доступен только для каждого пользователя/сеанса. Предлагаемые реализации всегда используют статические объекты. Почему вы этого не сделали?

person Emanuele Greco    schedule 27.09.2011
comment
Спасибо, на данный момент я запутался. Конечно, оказалось, что в приложении была ошибка, из-за которой переменная Session не была установлена... - person dragonfly; 28.09.2011

HttpContext.Current не является членом экземпляра, это статический член. Так что это потокобезопасно. И он возвращает экземпляр HttpContext, но он возвращает отдельный экземпляр для каждого запроса — может быть несколько потоков, обрабатывающих запросы, но каждый запрос получит отдельный экземпляр HttpContext. Таким образом, любой заданный экземпляр не используется несколькими потоками, и безопасность потоков не является проблемой.

Поэтому, если вы вручную не запускаете несколько собственных потоков для одного запроса, вы потокобезопасны.

person Joe White    schedule 27.09.2011
comment
Это неправда. IIS будет запускать новые потоки при достижении определенных нагрузок, и если вы сохраняете информацию о конфигурации или что-то еще в статической переменной, эти данные не будут доступны из нового потока. - person Don Rolling; 25.09.2012
comment
@DonRolling, есть цитата за это? Я никогда не слышал, чтобы IIS запускал более одного потока для одного и того же запроса, и я не уверен, что это вообще может означать. - person Joe White; 26.09.2012
comment
У меня нет цитаты, но проблема случилась со мной. Это не происходит во время одного запроса. Это происходит, если вы храните что-то вроде значений конфигурации базы данных в статической переменной. Если IIS начинает новый поток из-за трафика, эти значения конфигурации недоступны для нового потока. - person Don Rolling; 22.12.2012
comment
@DonRolling, вы путаете потоки с доменами приложений. Статические данные являются общими для всех потоков в домене приложения, поэтому эти значения будут доступны для нового потока. Только если он запустит новый домен приложения, вы получите новую копию статической переменной. И даже тогда ваш код инициализации все равно должен запускаться и инициализировать переменную, как это было в первом домене приложения. - person Joe White; 22.12.2012
comment
Дальнейшее обсуждение того, как ASP.NET переносит HttpContext между потоками, здесь: stackoverflow.com/questions/8109526 - person user423430; 12.05.2015

Потокобезопасность класса HttpContext довольно стандартна для .NET. Основное эмпирическое правило (если не указано явно) заключается в том, что статические члены являются потокобезопасными, а члены-экземпляры — нет.

В любом случае трудно сказать, почему ваша переменная сеанса имеет значение null, не изучая код, который ее устанавливает/сбрасывает. Или, возможно, вы вызываете свой метод get_AllocationActions из сеанса, отличного от того, в котором вы его установили. Опять же, вам может помочь дополнительный код.

person Ilia G    schedule 27.09.2011

Чтобы безопасно получить доступ к свойству сеанса, вы должны просто обернуть доступ в операторе блокировки и использовать объект SyncRoot класса сеанса.

person Lee Dale    schedule 27.09.2011