Поделиться через


Критические изменения ASP.NET 2.0 в IIS 7.0

Майк Володарский

Введение

ASP.NET приложения 2.0 в IIS 7.0 и более поздних версий по умолчанию размещаются в режиме интеграции ASP.NET. Этот новый режим обеспечивает множество интересных сценариев, включая использование ценных ASP.NET функций, таких как проверка подлинности с помощью форм для всего веб-сайта, и разработку новых модулей ASP.NET для выполнения таких действий, как перезапись URL-адресов, авторизация, ведение журнала и многое другое на уровне IIS. Дополнительные сведения об интеграции ASP.NET в IIS см. в разделе Интеграция ASP.NET с IIS7 и выше.

Делая приложения ASP.NET более мощными в IIS 7.0 и более поздних версиях, мы также приложили все усилия, чтобы существующие ASP.NET приложения продолжали работать при миграции на эту новую платформу. Это было серьезной проблемой для нас, так как мы перепроектировали весь основной двигатель ASP.NET, и в конце концов мы были весьма успешными в его решении. В результате большинство ASP.NET приложений должны работать без изменений.

В этой статье перечислены изменения в поведении, которые могут возникнуть при развертывании приложений ASP.NET в IIS 7.0 и более поздних версий в Windows Vista с пакетом обновления 1 (SP1) и Windows Server 2008. За исключением случаев, когда указано, эти критические изменения происходят только при использовании режима интеграции по умолчанию ASP.NET.

Использование классического режима ASP.NET

IIS 7.0 и более поздних версий также предоставляет возможность запуска ASP.NET приложений в устаревшем режиме классической интеграции ASP.NET, который работает так же, как ASP.NET работали в предыдущих версиях IIS. Однако настоятельно рекомендуется использовать обходной путь, если это возможно, чтобы изменить приложение на работу в режиме интеграции. При переходе в классический режим приложение не сможет воспользоваться преимуществами ASP.NET улучшений, которые стали возможными в интегрированном режиме, используя будущие функции корпорации Майкрософт и сторонних производителей, которым может потребоваться интегрированный режим. Используйте классический режим в качестве крайнего средства, если не удается применить указанное решение. Дополнительные сведения о переходе в классический режим см. в статье Изменение режима интеграции ASP.NET.

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

Критические изменения

Ошибки миграции

Эти ошибки возникают из-за изменений в применении некоторых ASP.NET конфигурации в интегрированном режиме. СЛУЖБЫ IIS автоматически обнаружит эту конфигурацию и выдаст ошибку с запросом на перенос приложения или переместит его в классический режим, если миграция неприемлема (см. критическое изменение 3 ниже).

1. ASP.NET приложениям требуется миграция при указании конфигурации в <httpModules> или <httpHandlers>

Вы получите сообщение 500 — внутренняя ошибка сервера. Это может быть ошибка HTTP 500.22 и ошибка HTTP 500.23: обнаружен параметр ASP.NET, который не применяется в режиме интегрированного управляемого конвейера. Это происходит потому, что ASP.NET модули и обработчики должны быть указаны в разделах IIS <handlers> и <modules> конфигурации в интегрированном режиме.

Обходной путь

A. Для правильной работы в режиме интеграции необходимо перенести конфигурацию приложения. Вы можете перенести конфигурацию приложения с помощью AppCmd:

> %windir%\system32\inetsrv\Appcmd migrate config "<ApplicationPath>"

Б. Вы можете выполнить миграцию вручную, переместив пользовательские записи в конфигурации и вручную <system.webServer>/<handlers> в <system.web>/<httpModules> разделы конфигурации и <system.webServer>/<modules> , удалив конфигурацию <httpHandlers> и <httpModules> ИЛИ добавив следующую команду <system.web>/<httpHandlers> в web.config приложения:

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
</system.webServer>

2. ASP.NET приложения выдают предупреждение, когда приложение включает олицетворение запроса, указывая <identity impersonate="true"> в конфигурации

Вы получите сообщение 500 — внутренняя ошибка сервера. Это ошибка HTTP 500.24: обнаружен параметр ASP.NET, который не применяется в режиме интегрированного управляемого конвейера. Это происходит из-за того, что ASP.NET интегрированный режим не может олицетворить удостоверение запроса на этапах конвейера BeginRequest и AuthenticateRequest.

Обходной путь

A. Если приложение не полагается на олицетворение запрашивающего пользователя на этапах BeginRequest и AuthenticateRequest (единственные этапы, на которых олицетворение невозможно в режиме интеграции), игнорируйте эту ошибку, добавив следующую команду в web.config приложения:

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
</system.webServer>

Б. Если приложение использует олицетворение в BeginRequest и AuthenticateRequest или вы не уверены, перейдите в классический режим.

3. Если конфигурация приложения содержит зашифрованный <identity> раздел, возникает ошибка конфигурации.

Вы получите сообщение 500 — внутренняя ошибка сервера. Это ошибка HTTP 500.19: не удается получить доступ к запрошенной странице, так как связанные данные конфигурации для страницы являются недопустимыми. Подробные сведения об ошибке указывают на то, что шифрование раздела конфигурации не поддерживается. Это происходит из-за того, что СЛУЖБА IIS пытается проверить <identity> раздел и не считывает шифрование на уровне раздела.

Обходной путь

A. Если у приложения нет проблемы с олицетворением запроса при критическом изменении 2, перенесите конфигурацию приложения с помощью AppCmd, как описано в разделе Критическое изменение 1:

> %windir%\system32\inetsrv\Appcmd migrate config "<ApplicationPath>"

Это обеспечит перенос остальной части конфигурации приложения и автоматически добавит следующее в web.config приложения, чтобы игнорировать <раздел identity> :

<system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
</system.webServer>

Б. Если в приложении возникла проблема с олицетворением запроса, перейдите в классический режим.

Проверка подлинности, авторизация и олицетворение

В режиме интеграции этапы проверки подлинности IIS и ASP.NET были унифицированы. Из-за этого результаты проверки подлинности IIS недоступны до этапа PostAuthenticateRequest, когда будут завершены оба метода проверки подлинности ASP.NET и IIS. Это приводит к следующим изменениям:

4. Приложения не могут одновременно использовать FormsAuthentication и WindowsAuthentication

В отличие от классического режима, невозможно использовать проверку подлинности с помощью форм в ASP.NET и по-прежнему требовать от пользователей проверки подлинности с помощью метода проверки подлинности IIS, включая проверку подлинности Windows, обычную проверку подлинности и т. д. Если включена проверка подлинности с помощью форм, все остальные методы проверки подлинности IIS, кроме анонимной проверки подлинности, должны быть отключены.
Кроме того, при использовании проверки подлинности с помощью форм действуют следующие изменения:

  • Переменной сервера LOGON_USER будет присвоено имя пользователя проверки подлинности на основе форм.

  • Невозможно будет олицетворять клиента, прошедшего проверку подлинности. Для олицетворения клиента, прошедшего проверку подлинности, необходимо использовать метод проверки подлинности, который создает пользователя Windows, а не проверку подлинности с помощью форм.

Обходной путь

A. Измените приложение, чтобы использовать шаблон, описанный в статье Реализация схемы двухуровневой проверки подлинности с использованием проверки подлинности на основе форм и другого метода проверки подлинности IIS в IIS 7.0.

5. Проверка подлинности Windows выполняется в ядре по умолчанию, что может привести к сбою HTTP-клиентов, отправляющих учетные данные в первоначальный запрос.

Проверка подлинности iis 7.0 и более поздних версий в режиме ядра включена по умолчанию. Это повышает производительность проверки подлинности Windows и упрощает развертывание протокола проверки подлинности Kerberos. Однако это может привести к сбою некоторых клиентов, отправляющих учетные данные Windows в исходном запросе из-за ограничения разработки в режиме проверки подлинности в режиме ядра. Обычные клиенты браузера не затрагиваются, так как они всегда отправляют исходный запрос анонимно.

Примечание

Это критическое изменение применяется как к классическому, так и к интегрированному режимам.

Обходной путь

A. Отключите проверку подлинности в режиме ядра, установив для userKernelMode значение false в разделе system.webServer/security/authentication/windowsAuthentication. Это также можно сделать с помощью AppCmd следующим образом:

> %windir%\system32\inetsrv\appcmd set config /section:windowsAuthentication /useKernelMode:false

6. Проверка подлинности по паспорту не поддерживается

Вы получите сообщение ASP.NET 500 — ошибка сервера: не удалось инициализировать объект PassportManager. Убедитесь, что microsoft Passport правильно установлен на сервере. Проверка подлинности по паспорту больше не поддерживается в Windows Vista и Windows Server 2008.

Примечание

Это критическое изменение применяется как к классическому, так и к интегрированному режимам.

7. HttpRequest.LogonUserIdentity создает исключение InvalidOperationException при доступе в модуле перед PostAuthenticateRequest

Вы получите сообщение ASP.NET 500 — ошибка сервера: этот метод можно вызвать только после события проверки подлинности. HttpRequest.LogonUserIdentity создает исключение InvalidOperationException при доступе до PostAuthenticateRequest, так как значение этого свойства неизвестно до тех пор, пока клиент не пройдет проверку подлинности.

Обходной путь

A. Измените код, чтобы не получить доступ к HttpRequest.LogonUserIdentity, пока не будет по крайней мере PostAuthenticateRequest

8. Олицетворение клиента не применяется в модуле на этапах BeginRequest и AuthenticateRequest

Пользователь, прошедший проверку подлинности, неизвестен до этапа PostAuthenticateRequest. Поэтому ASP.NET не олицетворяет пользователя, прошедшего проверку подлинности, для ASP.NET модулей, которые выполняются на этапах BeginRequest и AuthenticateRequest. Это может повлиять на приложение, если у вас есть пользовательские модули, которые полагаются на олицетворение клиента для проверки доступа к ресурсам или доступа к ним на этих этапах.

Обходной путь

A. Измените приложение, чтобы не требовать олицетворения клиента на этапах BeginRequest и AuthenticateRequest.

9. Определение метода DefaultAuthentication_OnAuthenticate в global.asax вызывает исключение PlatformNotSupportedException

Вы получите ASP.NET 500 — ошибка сервера: метод DefaultAuthentication.Authenticate не поддерживается режимом конвейера, интегрированным службами IIS. В режиме интеграции событие DefaultAuthenticationModule.Authenticate в не реализовано и, следовательно, больше не вызывается. В классическом режиме это событие возникает, если проверка подлинности не выполнялась.

Обходной путь

A. Измените приложение, чтобы не полагаться на событие DefaultAuthentication_OnAuthenticate. Вместо этого напишите IHttpModule, который проверяет, имеет ли httpContext.User значение NULL , чтобы определить, присутствует ли пользователь, прошедший проверку подлинности.

10. Приложения, реализующие WindowsAuthentication_OnAuthenticate в global.asax, не будут получать уведомления, если запрос является анонимным

Если вы определите метод WindowsAuthentication_OnAuthenticate в global.asax, он не будет вызываться для анонимных запросов. Это связано с тем, что анонимная проверка подлинности происходит после того, как модуль WindowsAuthentication может вызвать событие OnAuthenticate.

Обходной путь

A. Измените приложение, чтобы не использовать метод WindowsAuthentication_OnAuthenticate. Вместо этого реализуйте IHttpModule, который выполняется в PostAuthenticateRequest и проверяет HttpContext.User.

Ограничения запросов и обработка URL-адресов

Следующие изменения возникают из-за дополнительных ограничений на то, как IIS обрабатывает входящие запросы и их URL-адреса.

11. URL-адреса запроса, содержащие незакодированные символы "+" в пути (не в строке запроса), отклоняются по умолчанию

Вы получите сообщение об ошибке HTTP 404.11 — Не найдено: модуль фильтрации запросов настроен на отклонение запроса, содержащего двойную escape-последовательность. Эта ошибка возникает из-за того, что службы IIS по умолчанию настроены для отклонения попыток двойного кодирования URL-адреса, которые обычно представляют попытку выполнить атаку канонизации.

Обходной путь

A. Приложения, которым требуется использовать символ "+" в URL-пути, могут отключить эту проверку, задав атрибут allowDoubleEscaping в разделе конфигурации system.webServer/security/requestFiltering в web.config приложения. Однако это может сделать приложение более уязвимым для вредоносных URL-адресов:

<system.webServer>
    <security>
        <requestFiltering allowDoubleEscaping="true" />
    </security>
</system.webServer>

12. Запросы со строками запросов больше 2048 байт будут отклонены по умолчанию

Вы получите сообщение ОБ ошибке HTTP 404.15 — Не найдено: модуль фильтрации запросов настроен на отклонение запроса, если строка запроса слишком длинна. Службы IIS по умолчанию настроены так, чтобы отклонять строки запросов длиной более 2048 байт. Это может повлиять на приложение, если оно использует большие строки запросов или использует функции ASP.NET без файлов cookie, такие как проверка подлинности с помощью форм и другие, которые совокупно превышают заданное ограничение на размер строки запроса.

Примечание

Это критическое изменение применяется как к классическому, так и к интегрированному режимам.

Обходной путь

A. Увеличьте максимальный размер строки запроса, задав атрибут maxQueryString в элементе requestLimits в разделе конфигурации system.webServer/security/requestFiltering в web.config приложения:

<system.webServer>
    <security>
    <requestFiltering>
        <requestLimits maxQueryString="NEW_VALUE_IN_BYTES" />
    </requestFiltering>
    </security>
</system.webServer>

Изменения в обработке заголовков ответа

Эти изменения влияют на то, как приложение создает заголовки ответов.

13. IIS всегда отклоняет новые строки в заголовках ответов (даже если ASP.NET enableHeaderChecking имеет значение false).

Если приложение записывает заголовки с разрывами строк (любое сочетание \r или \n), вы получите ASP.NET 500 — ошибка сервера: значение не попадает в ожидаемый диапазон. СЛУЖБЫ IIS всегда отклоняют любые попытки создания заголовков ответов с разрывами строк, даже если asp. Поведение net enableHeaderChecking отключено. Это делается, чтобы предотвратить атаки на разделение заголовков.

Примечание

Это критическое изменение применяется как к классическому, так и к интегрированному режимам.

14. Если ответ пуст, заголовок Content-Type не подавляется.

Если приложение задает заголовок Content-Type, он останется там, даже если ответ очищен. Запросы на ASP.NET типов контента обычно содержат "Content-Type: text/html" в ответах, если приложение не переопределяет.

Обходной путь

A. Хотя это обычно не должно иметь критического эффекта, вы можете удалить заголовок Content-Type, явно присвоив свойству HttpResponse.ContentTypeзначение NULL при очистке ответа.

15. При очистке заголовков ответов с помощью HttpResponse.ClearHeaders заголовки ASP.NET по умолчанию не создаются, что может привести к отсутствию закрытого заголовка Cache-Control: который предотвращает кэширование ответа на клиенте.

HttpResponse.ClearHeaders не создает заголовки ответов по умолчанию ASP.NET, включая "Content-Type: text/html" и "Cache-Control: private", как это делается в классическом режиме. Это связано с тем, что ASP.NET модули могут вызывать этот API для запросов к любому типу ресурсов, поэтому создание заголовков ASP.NET не подходит. Отсутствие заголовка Cache-Control может привести к тому, что некоторые подчиненные сетевые устройства кэшируют ответ.

Обходной путь

A. Измените приложение, чтобы вручную создать закрытый заголовок Cache-Control: при очистке ответа, если требуется предотвратить кэширование на подчиненных сетевых устройствах.

Изменения в обработке событий приложения и модуля

Эти изменения влияют на процесс обработки событий приложения и модуля.

16. Невозможно получить доступ к запросу через свойство HttpContext.Current в Application_Start в global.asax

Если приложение обращается к текущему контексту запроса в методе Application_Start в global.asax в рамках инициализации приложения, вы получите сообщение ASP.NET 500 — ошибка сервера: запрос недоступен в этом контексте. Эта ошибка возникает из-за того, что ASP.NET инициализация приложения отделяется от запроса, который ее активирует. В классическом режиме можно было косвенно получить доступ к контексту запроса, перейдя к свойству HttpContext.Current. В режиме интеграции этот контекст больше не представляет фактический запрос, поэтому попытки получить доступ к объектам Request и Response создают исключение.

Обходной путь

A. Подробное описание этой проблемы и доступные решения см. в статье Запрос недоступен в этом исключении контекста в Application_Start .

17. Порядок выполнения обработчиков событий модуля может отличаться от порядка выполнения в классическом режиме

Существуют следующие различия.

  • Для каждого события обработчики событий для каждого модуля выполняются в порядке, в котором модули настраиваются в разделе конфигурации <modules> . Обработчики событий Global.asax выполняются последним.

  • Модули, которые регистрируются для событий PreSendRequestHeaders и PreSendRequestContent, получают уведомления в обратном порядке, в котором они отображаются в <modules> разделе конфигурации.

  • Для каждого события синхронные обработчики событий для каждого модуля выполняются перед асинхронными обработчиками. В противном случае обработчики событий выполняются в том порядке, в котором они зарегистрированы.

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

Инструкции по решению:

A. Измените порядок модулей, для которых возникла проблема с упорядочением, в разделе конфигурации system.webServer/modules .

18. ASP.NET модулях на ранних этапах обработки запросов будут видеть запросы, которые ранее могли быть отклонены службами IIS перед вводом ASP.NET, включая модули, работающие в BeginRequest, которые видят анонимные запросы для ресурсов, требующих проверки подлинности.

ASP.NET модули могут выполняться на любых этапах конвейера, доступных для собственных модулей IIS. Поэтому запросы, которые ранее могли быть отклонены на этапе проверки подлинности (например, анонимные запросы для ресурсов, требующих проверки подлинности) или на других этапах до ввода ASP.NET могут выполняться ASP.NET модулях. Это поведение предназначено для того, чтобы позволить модулям ASP.NET расширить службы IIS на всех этапах обработки запросов.

Обходной путь

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

Другие изменения приложения

Другие изменения в поведении ASP.NET приложений и API.

19. DefaultHttpHandler не поддерживается, поэтому приложения, использующие подклассы DefaultHttpHandler, не смогут обслуживать запросы.

Если приложение использует DefaultHttpHandler или обработчики, производные от DefaultHttpHandler, оно будет работать неправильно. В режиме интеграции обработчики, производные от DefaultHttpHandler, не смогут передать запрос обратно в IIS для обработки и вместо этого обслуживают запрошенный ресурс в виде статического файла. Встроенный режим позволяет ASP.NET модулям выполняться для всех запросов без использования DefaultHttpHandler.

Обходной путь

A. Измените приложение, чтобы использовать модули для обработки запросов для всех запросов, а не использовать сопоставление с подстановочными знаками для сопоставления ASP.NET со всеми запросами, а затем использовать производные обработчики DefaultHttpHandler для передачи запроса обратно в IIS.

20. Запись в ответ возможна после возникновения исключения

В режиме интеграции можно записать и отобразить дополнительный ответ, записанный после возникновения исключения, как правило, в модулях, которые подписываются на события LogRequest и EndRequest. Это не происходит в классическом режиме. Если во время запроса возникает ошибка и приложение записывает в ответ EndRequest после возникновения исключения, будут отображаться сведения об ответе, записанные в EndRequest. Это влияет только на запросы, которые содержат необработанные исключения. Чтобы избежать записи в ответ после исключения, приложение должно проверка HttpContext.Error или HttpResponse.StatusCode перед записью в ответ.

21. Невозможно использовать API ClearError, чтобы предотвратить запись исключения в ответ, если исключение произошло на предыдущем этапе конвейера

Обходной путь

A. Измените приложение на вызов Server.ClearError из обработчика событий Application_OnError, который возникает при возникновении исключения.

22. HttpResponse.AppendToLog не добавляет строку запроса к URL-адресу автоматически.

При использовании HttpResponse.AppendToLog для добавления настраиваемой строки к URL-адресу, зарегистрированному в файле журнала запросов, необходимо вручную добавить строку запроса к строке, передаваемой в этот API. Это может привести к потере строки запроса из зарегистрированного URL-адреса при использовании этого API.

Обходной путь

A. Измените приложение, чтобы вручную добавить httpResponse.QueryString.ToString() к строке, передаваемой в HttpResponse.AppendToLog.

Другие изменения

Прочие изменения.

23. ASP.NET параметры потоков не используются для управления параллелизмом запросов в интегрированном режиме

Параметры minFreeThreads, minLocalRequestFreeThreads в разделе конфигурации system.web/httpRuntime и параметр maxWorkerThreads в разделе конфигурации processModel больше не управляют механизмом потоков, используемым ASP.NET. Вместо этого ASP.NET использует пул потоков IIS и позволяет управлять максимальным числом одновременно выполняемых запросов, задав значение DWORD MaxConcurrentRequestsPerCPU (по умолчанию — 12), расположенное в ключе HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ASP.NET\2.0.50727.0. Этот параметр является глобальным и не может быть изменен для отдельных пулов приложений или приложений.

Обходной путь

A. Чтобы управлять параллелизмом приложения, задайте параметр MaxConcurrentRequestsPerCPU.

24. ASP.NET очереди приложений не используются в режиме интеграции, поэтому счетчик производительности "ASP.NET приложения\запросы в очереди приложений" всегда будет иметь значение 0.

ASP.NET не использует очереди приложений в режиме интеграции.

25. IIS 7.0 и более поздних версий всегда перезапускается ASP.NET приложения при внесении изменений в корневой файл web.config приложения, поэтому атрибуты waitChangeNotification и maxWaitChangeNotification не оказывают влияния.

IIS 7.0 и более поздних версий также отслеживает изменения в файлах web.config и приводит к перезапуску приложения ASP.NET, соответствующего этому файлу, без учета параметров уведомления об изменениях ASP.NET, включая атрибуты waitChangeNotification и maxWaitChangeNotification в разделах конфигурации system.web/httpRuntime.

Мы надеемся, что переход на интегрированный режим в IIS 7.0 и более поздних версий будет как можно более безболезненный, поэтому вы сможете сразу же приступить к применению функций IIS и возможностей интегрированных ASP.NET в приложениях.

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