У нас есть приложение MVC.NET, которое встречается с фатальными ошибками, когда оно перезапускает. В нашем обработчике событий Session_Start мы добавляем идентификатор сессии к словарю. В обработчике Session_End мы удаляем его. Рассмотрите следующую последовательность запросов:
ПОЛУЧИТЕ home.mvc
<перезапуски приложения>
ПОЛУЧИТЕ main.css
ПОЛУЧИТЕ banner.jpg
ПОЛУЧИТЕ somedata.mvc
...
Из-за пути проектируется приложение, этот вид последовательности происходит справедливо часто, если Вы делаете восстанавливание, в то время как приложение открыто в окне браузера. Это ужасно не коснулось бы за исключением того, что я вижу его в продуктивных средах также. Например, это произойдет (хотя редко) при редактировании web.config.
Запросы после перезапуска происходят все из-за ссылок в домашней странице или вызовах Ajax от JavaScript.
То, что я наблюдаю, - то, что.NET обрабатывает первые 5 запросов параллельно. Каждый такой запрос заставляет это запускать событие Session_Start. После короткого времени это запускает времена события 3 Session_End. Чтобы быть ясным, каждый Session_Start соответствует той же самой сессии. У них всех есть тот же идентификатор сессии, и свойство IsNewSession верно для всех объектов состояния сеанса. Кроме того, события Session_End не соответствуют уничтожаемой сессии. Сессия сохраняется, наряду с любыми данными, хранившими в состоянии сеанса.
Я должен или препятствовать тому, чтобы он запустил Session_Start несколько раз, или выяснить, как сказать, когда Session_End действительно не означает, что сессия закончилась.
Ответ на этот вопрос оказался довольно прямым, хотя поведение определенно сбивало с толку.
Обычно MVC синхронизирует все запросы к приложению с помощью блокировки состояния сеанса приложения (поскольку http-модуль MVC отмечен как требующий состояния сеанса). В моем сценарии приложение перезапускается после обслуживания главной страницы. Таким образом, когда приходят запросы, относящиеся к основной странице, для этого идентификатора сеанса еще нет состояния сеанса, и запросы выполняются параллельно.
Я вижу 5 параллельных запросов, потому что я разрабатываю для XP, а настольные версии IIS ограничены 5 параллельными запросами. Поскольку объект состояния сеанса не существует ни для одного из этих запросов, каждый запрос создает новый объект состояния сеанса и запускает Session_Start. Четыре запроса относятся к методам действий MVC. Поскольку для этого требуется состояние сеанса, .NET пытается синхронизировать созданные объекты состояния сеанса с резервным хранилищем после завершения запросов.
Успешной может быть только первая синхронизация. .NET просто отбрасывает три дополнительных объекта состояния сеанса и запускает Session_End для каждого из них. .NET не пытается синхронизировать пятый объект состояния сеанса с резервным хранилищем, поскольку он был создан для асинхронного модуля http, который помечен как требующий состояния сеанса только для чтения.
Итак, исправление состоит из двух частей:
(1) В моем обработчике Session_Start я теперь проверяю, доступен ли объект состояния сеанса только для чтения. Если да, то я немедленно возвращаюсь, ничего не делая. .NET не будет запускать соответствующий Session_End, и поэтому все, что я делаю, в любом случае не будет очищено должным образом.
(2) Теперь я веду счетчик ссылок в моем словаре. Я увеличиваю счетчик каждый раз, когда обработчик Session_Start пытается добавить идентификатор сеанса, и уменьшаю его каждый раз, когда Session_End пытается его удалить. Когда счетчик достигает 0, я удаляю идентификатор сеанса из своего словаря.
Идентификатор сессии можно использовать повторно, если клиент посылает вам значение, срок действия которого истек. Прочитайте об атрибуте regenerateExpiredSessionId элемента
Вам также может быть интересно здесь: