Подтвердить что ты не робот

Session имеет значение null в AcquireRequestState при загрузке имени виртуального каталога в браузере, но не имеет значения null при загрузке Default.aspx

У меня есть приложение ASP.NET 4.0 WebForms. Мне нужно получить доступ к HttpContext.Current.Session и установить значение в событии AcquireRequestState (или событие после него) в Global.asax, и я нашел своеобразное поведение.

Скажем, у меня есть виртуальный каталог в IIS (версия 7 в моем случае) под названием Foo. При этом Default.aspx. Пример файла Global.asax ниже:

<%@ Application Language="C#" %>

<script runat="server">
    void Application_AcquireRequestState(object sender, EventArgs e)
    {
        HttpContext.Current.Session["key"] = "value";
    }
</script>

Когда я посещаю http://localhost/Foo/Default.aspx в моем браузере, он работает отлично. Когда я посещаю http://localhost/Foo/, я получаю NullReferenceException, где я устанавливаю значение в сеансе. Единственное изменение - это URL в браузере. Они попадают на одну и ту же страницу, но структура ведет себя по-разному, основываясь на том, содержит ли URL только имя папки или содержит файл aspx.

Проверка if (HttpContext.Current.Session != null) для меня не является опцией, потому что мне нужно установить значение в сеансе с каждым запросом, который не подлежит обсуждению.

Есть ли в IIS параметр конфигурации, который мне не хватает, или это ошибка/забытая функция?

Ответ на еще один вопрос намекнул на то, что IIS не загружает сеанс для каждого вида запроса, например, таблицы стилей не нуждаются в сеансе. Возможно, такое поведение происходит, потому что IIS не может сказать заранее, если это имя папки приведет к выполнению aspx файла или если он предоставит статический HTML файл?

Обновление: Я даже попробовал переупорядочить документы по умолчанию, которые IIS ищет, чтобы "default.aspx" находился в верхней части списка, например

  • default.aspx
  • Default.asp
  • Default.htm
  • ...

И я все еще получаю ту же проблему.

Update:

Обработчик событий запускается только один раз, потому что он приводит к NullReferenceException. Я сделал некоторое дополнительное чтение, и я знаю, что ASP.NET запускает эти события для каждого запроса, даже для файлов CSS или JavaScript. Кроме того, объект сеанса не загружается для статических файлов, потому что нет кода, который обращается к сеансу, поэтому нет необходимости загружать объект. Тем не менее, самый первый запрос - это запрос на веб-страницу, для которой потребуется сеанс, а сеанс имеет значение null.

@Дмитрий Шевченко спросил:

Сначала добавьте проверочный чек if (HttpContext.Current.Session != null), чтобы не было выброшено NullReferenceException. Затем попробуйте увидеть, возможно, событие будет запущено во второй раз, с сеансом.

Измененный код:

void Application_AcquireRequestState(object sender, EventArgs e)
{
    if (HttpContext.Current.Session != null)
    {
        HttpContext.Current.Session["key"] = "value";
    }
}

Я установил точку прерывания в выражении if. Я видел это событие четыре раза:

  • session is null
  • session is null
  • сеанс не null
  • session is null

Когда вы продолжаете каждый раз переходить к коду, только когда он начал выполнять Default.aspx и его код, у меня есть сеанс. У меня на самом деле была открыта веб-страница в Firefox и она отслеживала сетевые запросы. Первый запрос был для http://localhost/Foo/.

Далее я установил точку останова в Application_BeginRequest и получил следующие события:

  • BeginRequest
  • AcquireRequestState
  • BeginRequest
  • AcquireRequestState
  • BeginRequest
  • AcquireRequestState (сеанс не является нулевым)
  • Выполнить Default.aspx(/Foo возвращает ответ браузеру)
  • BeginRequest
  • AcquireRequestState (сеанс снова null)

В # 9 запрос AJAX в браузере http://localhost:54859/8fad4e71e57a4caebe1c6ed7af6f583a/arterySignalR/poll?transport=longPolling&connectionToken=...&messageId=...&requestUrl=http%3A%2F%2Flocalhost%2FFoo%2F&browserName=Firefox&userAgent=Mozilla%2F5.0+(Windows+NT+6.1%3B+WOW64%3B+rv%3A41.0)+Gecko%2F20100101+Firefox%2F41.0&tid=4&_=1445346977956 висит в ожидании ответа.

4b9b3361

Ответ 1

Я нашел обсуждение о различиях между показом страницы по ее явному URL-адресу и службой документа по умолчанию.

С MVC и WebAPI был введен новый HttpModule: ExtensionlessUrlHandler. Я считаю, что ваше событие, срабатывающее несколько раз (и только один раз с доступным сеансом), может быть вызвано этим модулем или другой (повторной) логикой маршрутизации ASP.NET, которая фактически перенаправляет ASP.NET для обработки Default.aspx.

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

Суть в том, что вы не должны полагаться на доступ к сеансу каждый раз, когда ваше событие запущено. Но можно с уверенностью предположить, что вы можете получить доступ к сеансу хотя бы один раз, когда используете страницу ASP.NET. Следовательно, вот как выглядит ваш код:

void Application_AcquireRequestState(object sender, EventArgs e)
{
    if (HttpContext.Current.Session != null)
    {
        HttpContext.Current.Session["key"] = "value";
    }
}

Ответ 2

Что происходит, так это то, что определенные события, которые происходят до передачи запроса на страницу, вызывают это событие. Аналогично, это событие может быть поднято не на страницах ASPX. Я думаю, вам нужно сделать несколько вещей:

  • установите AutoEventWireUp в false в вашем коде страницы (в default.aspx). Это кажется странным и несвязанным, но, видимо, это может решить вашу проблему.
  • проверьте null. В самом деле. Поскольку из всех событий вас интересуют только те события, которые возникли на странице ASPX (или аналогичной), которая фактически имеет состояние сеанса. Поскольку каждый истинный запрос от пользователя всегда создает сеанс, вы можете просто фильтровать его, не опасаясь, что вы пропустите определенные события. Как вы видели, в каждом цикле всегда есть хотя бы одно событие, которое имеет установленный сеанс.
  • используйте PostAcquireRequestState, тем более естественно использовать (или использовать PreRequestHandlerExecute), потому что на этом событии все состояние гарантированно будет установлен и заполнен.

Ответ 3

Я думаю, что ваш URL-адрес запроса не содержит ".aspx", правильно?

Версия IIS7 + имеет конфигурацию whitch не будет использовать "SessionStateModule", если полагает, что обработчик запроса не управляется. Handler

Итак, решение легко

Найдите свой web.config, затем добавьте свойство

<modules runAllManagedModulesForAllRequests="true">
     ....
</modules>

runAllManagedModulesForAllRequests = "true" сказать asp.net все равно использовать все модули

надежды на помощь

Ответ 4

Когда ресурс имеет ошибку компиляции, тогда сеанс будет равен null даже в Application_PostAcquireRequestState