Независимо от того, какую модель страницы вы использовали (одномодульную страницу или страницу с внешним кодом поддержки), ваши файлы *.aspx (как и любые связанные файлы с кодом поддержки) динамически компилируются в действительный компоновочный блок .NET. Этот компоновочный блок затем обрабатывается в рамках рабочего процесса ASP.NET (aspnet_wp.exe) в пределах собственного домена приложения (для получения более подробной информации о доменах приложений см. главу 13). Однако метод компиляции компоновочного блока Web-узла в ASP.NET 2.0 оказывается совершенно иным.
Цикл компиляции одномодульных страниц
При использовании модели одномодульной страницы, HTML-разметка, блоки ‹script› и определения Web-элементов управления динамически компилируются в тип класса, производный от System.Web.UI.Page.
Имя этого класса получается из имени файла *.aspx с помощью присоединения суффикса _аspx к имени файла (например, страница MyPage.aspx порождает тип класса с именем MyPage_aspx). На рис. 23.15 показана общая схема соответствующего процесса.
Рис. 23.15. Модель компиляции одномодульных страниц
Этот динамически компилируемый компоновочный блок устанавливается в определенный средой выполнения подкаталог в папке ‹%windir%›Microsoft.NET\ Framework\v2.0.50215\Temporary ASP.NET Files\root. Имя пути после \root зависит от целого ряда факторов (хеш-кода и т.п.). но в конце концов там можно найти соответствующие файлы *.dll (и файлы поддержки). На рис. 23.16 показан пример одного такого компоновочного блока.
Рис. 23.16. Автоматически сгенерированный компоновочный блок ASP.NET
Цикл компиляции многомодульных страниц
Процесс компиляции страницы, построенной по модели с внешним кодом поддержки, подобен процессу компиляции одномодульной страницы. Однако получающийся при этом тип, производный от System.Web.UI.Page, компонуется из трех файлов (да, именно из трех, а не из ожидаемых двух).
Взглянув на предыдущий пример CodeBehindPageModel, вспомните о том, что файл Default.aspx связывается с парциальным классом _Default, размещенным в файле внешнего кода поддержки. Если вы имеете опыт работы с ASP.NET 1.x, то можете спросить, что же при этом происходит с описаниями членов-переменных для различных Web-элементов управления и с программным кодом в пределах InitializeComponent, в частности с программной логикой обработки событий. В ASP.NET 2.0 все это собирается в третьем "файле", генерируемом в памяти. Фактически это не совсем файл, а представление парциального класса в памяти (рис. 23.17).
В рамках этой модели объявленные в файле *.aspx Web-элементы управления используются для построения дополнительного парциального класса, определяющего все члены-переменные интерфейса пользователя и программную логику конфигурации, которые в ASP.NET 1.x обычно находились в пределах метода InitializeComponent, а в данном случае остаются для нас невидимыми. Этот парциальный класс в процессе компиляции объединяется с файлом внешнего кода поддержки, чтобы в результате получился
В любом случае после создания компоновочного блока в ответ на исходный HTTP-запрос этот компоновочный блок будет использоваться многократно для всех последующих запросов, не требуя перекомпиляции. Вот почему первый запрос страницы *.aspx может занимать много времени, а последующие обращения к той же страницы оказываются намного быстрее.
Рис. 23.17. Модель компиляции многомодульных страниц
Замечание. В ASP.NET 2.0 теперь можно выполнить предкомпиляцию всех (или некоторого подмножества) страниц Web-узла с помощью специального инструмента командной строки aspnet_compiler.exe. Более конкретная информация по этому вопросу имеется в документации .NET Framework 2.0 SDK.
Цепочка наследования типа Page
Как вы только что убедились, готовый генерируемый класс, представляющий файл *.aspx, получается из System.Web.UI.Page. Подобно любому базовому классу, этот тип обеспечивает полиморфный интерфейс всем производным типам. Однако тип Page является не единственным членом в иерархии наследования. Если найти тип Page (в пределах компоновочного блока System.Web.dll) в окне обозреватели объектов Visual Studio 2005, то вы увидите, что этот тип "принадлежит" типу TemplateControl, который, в свою очередь, "принадлежит" Control, а последний "принадлежит" Object (рис. 23.18).