Анатомия приложений ASP.NET
Модель компиляции ASP.NET
Как нам стало известно ранее, платформа .NET Framework имеет особую, двухэтапную модель компиляции приложений. Эта модель подразумевает получения промежуточного кода на языке MSIL, который впоследствии преобразуется в машинный код.
Поскольку приложения ASP.NET работают в рамках общей среды исполнения платформы .NET Framework, они также работают на основе этого механизма. Несмотря на это, платформа ASP.NET имеет свои особенности компиляции приложений.
Вообще, если рассматривать способы исполнения веб-приложений, то можно выделить два направления:
- интерпретируемые приложения;
- компилируемые приложения.
Интерпретируемые приложения исполняют исходный текст программы построчно. Интерпретатор в этом случае считывает очередную строку из текста программы и исполняет её, после чего переходит к следующей строке. Общий алгоритм подобного подхода можно описать следующей схемой.
К основным недостаткам подобного подхода относится невысокая скорость исполнения программного кода. Также, при подобном подходе нет возможности проверить весь листинг кода на наличие ошибок. Например, если исходный код программы состоит из 100 строк и в строке 50 содержится ошибка, то первые 49 строк будут успешно исполнены, а на строке 50 будет выдана ошибка. Такое поведение не всегда желательно, поэтому данный способ мало популярен в современной разработке приложений.
Платформа ASP.NET использует альтернативный подход к исполнению приложений, а именно компиляцию исходных файлов в бинарный исполняемый файл перед выполнением. В этом случае перед запуском приложения исходный файл преобразуется в исполняемый файл. Это позволяет отследить часть ошибок на этапе компиляции (например, синтаксические ошибки). Кроме того, в момент исполнения приложения не требуется выполнять проверку и разбор синтаксических конструкций языка, что увеличивает производительность таких приложений относительно интерпретируемых приложений.
Схема исполнения компилируемых приложений выглядит следующим образом.
Как мы увидим в последующих лекциях (когда будем подробно разбирать механизмы работы страниц ASP.NET), каждая страница состоит из разметки (HTML и ASPX кода) и программного кода. Особенностью платформы ASP.NET является то, что все элементы веб-приложения (страницы, элементы управления, обработчики и т.д.) компилируются, а не интерпретируются.
Однако, если с компиляцией программного кода на языке C# (который является частью страницы ASP.NET) все понятно, то каким же образом компилируется разметка страницы? Ведь разметка страницы, по сути, представляет собой обычный текст на языке HTML, который должен обрабатываться бразуером, но для сервера он является обычной последовательностью символов. Давайте разберемся в этом вопросе более подробно.
Если рассмотреть страницу ASP.NET с точки зрения объектной модели, то каждая страница является классом, который в свою очередь является наследником базового класса Page. С другой стороны в структуре проекта страница ASP.NET представляется двумя файлами – файлом разметки (.aspx) и файлом с программным кодом (.cs или .vb).
Если более внимательно рассмотреть файл содержащий программный код для страницы, то в нем можно заметить одну особенность – класс страницы (наследник класса Page) при определении содержит ключевое слово partial.
Ключевое слово partial при определении класса говорит компилятору о том, что описание данного класса может содержатся в нескольких файлах. Действительно, при компиляции страницы ASP.NET на основе файла разметки создается вторая часть этого класса. При компиляции такого класса он собирается в одно целое и компилируется в язык MSIL.
Схема процесса компиляции страницы ASP.NET в программный код может выглядеть следующим образом.
Каким образом разметка преобразуется в программный код? В общем случае разметка трансформируется в вызовы методов "Response.Write()", которые записывают информацию в выходной буфер, который пересылается клиенту. Таким образом, получается полностью скомпилированная страница, которая может запускаться на исполнение.
Для ускорения работы все скомпилированные страницы хранятся в специальной системной папке "C:\Windows\Microsoft.NET\[version]\Temporary ASP.NET Files\" (где [verison] – версия .NET Framework). Эта папка имеет следующую структуру.
Для каждого сайта создается своя папка, в которой присутствуют скомпилированные страницы. В каждой такой папке содержаться временные файлы и информация об исходной странице. Эта информация необходима для отслеживания изменения исходной страницы.
Поскольку существует возможность размещения на веб-сервере проекта в виде исходных файлов, то зачастую компиляция страниц ASP.NET производится в момент первого обращения к этой странице по протоколу HTTP. Из-за этого при первом обращении к страницам веб-приложения могут быть небольшие задержки. Для того, чтобы этого избежать можно выполнить предкомпиляцию приложения.
Предкомпиляция приложения – это процесс предварительной компиляции всех страниц веб-приложения с целью получения исполняемых сборок. Предкомпиляция веб-приложения может выполняться с целью исключения ситуации с задержкой ответа при первом обращении к странице, а также распространение веб-приложения в виде бинарных исполняемых сборок, а не исходных кодов.
Существует два варианта предкомпиляции веб-приложений:
предкомпиляция приложения с возможностью последующего обновления | в этом случае исходный код разметки страниц (.aspx) остается в неизменном виде и при изменении этой страницы на сервере она перекомпилируется при первом обращении; |
предкомпиляция приложения без возможности последующего обновления | в этом случае все файлы компилируются в бинарные сборки и изменение страниц на веб-сервере невозможно. |
Предкомпиляцию приложения можно выполнить двумя способами – с помощью Visual Studio и отдельной утилитой aspnet_compiler.
Для предкомпиляции приложения средствами Visual Studio необходимо выбрать пункт меню "Publish Web Site" и в появившемся окне задать адрес публикации и необходимые параметры.
Утилита aspnet_compiler поставляется в составе .NET Framework и может быть использована в случае, если Visual Studio в данный момент недоступна (например, требуется выполнить предкомпиляцию приложения прямо на сервере) или требуется автоматизировать процесс предкомпиляции.
Другой важной особенностью компиляции приложений ASP.NET является возможность разграничения области исполнения различных приложений. Поскольку в рамках одного сервера одновременно может исполняться несколько приложений, то разграничение работы приложений является важным моментом. Такое разграничение производится за счет доменов приложений.
Домен приложения – это .NET-аналог процесса в операционной системе. Основной задачей доменов приложения является разграничение зоны действия для различных веб-приложений. Такое разграничение необходимо для обеспечения безопасности. Например, при таком подходе невозможен сценарий, при котором некачественный код одного приложения выведет из строя другое веб-приложение.
Для каждого отдельного каталога на сервере создается отдельный домен приложения. Использование такой модели позволяет разграничить память, выделяемую каждому приложению. Кроме того, в рамках одного домена приложения совместно используются одни и те же ресурсы, находящиеся в памяти – глобальные данные приложения (Application), данные сеансов пользователей (Session), кэшированные данные (Cache) и др. Эта информация не является доступной напрямую другим приложениям, работающим за рамками данного домена приложения. Кроме того, все страницы ASP.NET и другие ресурсы совместно используют одни и те же конфигурационные настройки, которые наследуются из корневого файла web.config.
Каждое веб-приложение исполняется в рамках своего домена приложения. Для того чтобы приложение могло исполняться необходимо каким-то образом создать домен приложения. Для этого используется механизм отложенной инициализации. Этот механизм подразумевает то, что домен приложения не будет создан при старте сервера или в какое-то другое время. Домен приложения создается в момент первого обращения к нему. Такая модель используется для эффективного обновления приложения.
Время жизни приложения может зависеть от различных факторов. Домен приложения может быть закрыт в силу различных причин. Основные причины прекращения работы домена приложения:
- домен приложения закрывается при остановке или перезапуске web-сервера;
- домен приложения закрывается при длительном отсутствии активности в отношении данного приложения;
- домен приложения может закрываться при возникновении необработанной глобальной ошибки, которую не удалось отловить;
- домен приложения закрывается при обновлении ресурсов в рамках данного приложения;
- домен приложения можно закрыть принудительно, вызвав статический метод HttpRuntime.UnloadAppDomain().
Закрытие домена приложения при отсутствии активности обусловлено оптимизацией использования ресурсов операционной системы. При закрытии домена приложения освобождаются ресурсы, занимаемые этим доменом, например оперативная память.
Одной из важных особенностей ASP.NET является модель обновления страницы. Эта модель подразумевает, что для обновления какой-либо страницы не нужно останавливать работу веб-сервера. При изменении, добавлении или удаления какого-либо ресурса инфраструктура ASP.NET автоматически создает новый домен приложения, в который загружаются обновленные ресурсы и в котором обрабатываются все последующие запросы. Старый домен приложения существует до тех пор, пока не будут обработаны все старые запросы. Таким образом, в один момент времени может существовать два домена одного и того же приложения, один из них будет обрабатывать старые запросы, другой – новые.
В момент исполнения программного кода той или иной сборки, среда исполнения CLR блокирует эту сборку на время исполнения кода. По этой причине ASP.NET не размещает исполняемые файлы в папке с приложением, а вместо этого во время компиляции использует теневое копирование. Для этого в момент компиляции все исполняемые файлы помещаются в папку "C:\Windows\Microsoft.NET\[version]\Temporary ASP.NET Files\". Очень важно, что наряду с бинарными исполняемыми файлами в этой папке хранятся XML-описания сущностей ASP.NET. Это позволяет обнаружить изменения в исходных файлах и, в случае необходимости, перекомпилировать их.
Краткие итоги
Компиляция страниц ASP.NET имеет свою специфику по сравнению с компиляцией остальных типов приложений. Все сущности ASP.NET (страницы, элементы управления и т.д.) компилируются в бинарные исполняемые сборки. При этом существует специальная системная папка, в которой расположены все исполняемые сборки. Компиляция страницы ASP.NET в исполняемую сборку происходит в момент первого обращения к этой странице. Из-за этого могут возникать небольшие задержки генерации страницы в момент первого обращения. Для того чтобы этого избежать существует механизм предкомпиляции приложений. Важную роль в компиляции и обновлении приложений ASP.NET играют домены приложения – они позволяют разграничить исполнение различных приложений, которые расположены на одном сервере.