Чтобы лучше ответить на оригинальный вопрос:
Фон
Каждый запрос одной страницы раскручивает новый объект Session
, а затем раздувает его из хранилища сеансов. Для этого он использует cookie, предоставленный клиентом, или специальную конструкцию пути (для сеансов без cookie). С помощью этого идентификатора сеанса он обращается к хранилищу сеансов и десериализует (поэтому все провайдеры, кроме InProc должны быть сериализуемыми) нового объекта сеанса.
В случае провайдера InProc просто вручает вам ссылку, хранящуюся в HttpCache
с ключом идентификатора сеанса. Вот почему поставщик InProc сбрасывает состояние сеанса при перезапуске AppDomain
(а также почему несколько веб-серверов не могут совместно использовать состояние сеанса InProc .
Этот вновь созданный и надутый объект застрял в коллекции Context.Items
, поэтому он доступен на время запроса.
Любые изменения, которые вы вносите в объект Session
, затем сохраняются в конце запроса к хранилищу сеансов путем сериализации (или в случае InProc запись HttpCache
обновляется).
Так как Session_End
запускается без текущего запроса на лету, объект Session
запускается ex-nilo, информация недоступна. При использовании состояния сеанса InProc истечение срока действия HttpCache
инициирует событие обратного вызова в ваше событие Session_End
, поэтому запись сеанса доступна, но все еще является копией того, что в последний раз сохранялось в HttpContext.Cache
. Это значение сохраняется в свойстве HttpApplication.Session
внутренним методом (называемым ProcessSpecialRequest
), где оно затем доступно. Во всех остальных случаях он внутренне исходит из значения HttpContext.Current.Session
.
Ваш ответ
Поскольку Session_End всегда срабатывает против нулевого контекста, вы должны ВСЕГДА использовать this.Session в этом событии и передавать объект HttpSessionState в код трассировки. Во всех других контекстах, это прекрасно, чтобы выбрать из HttpContext.Current.Session
и затем передать в код трассировки. НЕ , однако, пусть код трассировки дойдет до контекста сеанса.
Мой ответ
Не используйте Session_End
, если только вы не знаете, что хранилище сеансов, которое вы используете, поддерживает Session_End
, которое оно делает , если возвращает true
из SetItemExpireCallback
. Единственный встроенный магазин - это магазин InProcSessionState
. Можно написать хранилище сеансов, которое делает это, но вопрос о том, кто будет обрабатывать Session_End
, является двусмысленным, если имеется несколько серверов.