Программирование уровня приложения ASP.NET
Виртуальный каталог, который мы создаем в самом начале разработки сайта, при исполнении страниц ассоциируется с отдельным приложением. Приложение является отдельной программной единицей, изолированной при исполнении от страниц других виртуальных каталогов. Все, что находится в виртуальном каталоге, относится к приложению.
Исполняемое средой ASP.NET приложение называется доменом (по аналогии с процессом при исполнении приложения локального стола). В отличие от локальных приложений, конечный пользователь никогда не запускает приложение ASP.NET напрямую. Он запускает броузер на своем локальном компьютере и запрашивает определенный URL. Этот запрос получет Web-сервер и передает его среде исполнения ASP.NET (рабочему процессу), которая выделяет в памяти домен для виртуального каталога и загружает в него код адресуемой страницы. Таким образом, домен приложения создается рабочим процессом при первом запросе любой страницы или Web-службы виртуального каталога.
Web-страницы и Web-службы одного виртуального каталога выполняются в одном и том же домене. Содержимое другого виртуального каталога выполняется в своем домене. Выполнение приложений из разных виртуальных каталогов в отдельных изолированных доменах гарантирует, что одно приложение не сможет оказывать влияние на работу другого, в том числе видеть его данные, хранящиеся в оперативной памяти. За этим строго следит общеязыковая среда выполнения CLR.
Все Web-страницы или Web-службы совместно используют одни и те же ресурсы, которые недоступны другим приложениям. Конфигурационные настройки среды исполнения, помещенные в файл Web.config виртуального каталога приложения, действуют только в пределах этого приложения. Страницы, требующие еще более индивидуальных настроек, могут быть помещены в подкаталоги со своими файлами Web.config.
Приложение может состоять из следующих компонентов:
- Web-страницы (файлы .aspx) - основные рабочие единицы любого приложения
- Web-службы (файлы .asmx) - выполняют полезную работу для сторонних приложений
- Файлы отделенного кода (.cs) - содержат исполнимый код для программного управления объектами, определяемыми в интерфейсной части страницы
- Конфигурационные файлы (Web.config) - содержат настройки среды исполнения (рабочего процесса) как для всего приложения в целом, так и для групп страниц, расположенных в подкаталогах виртуального каталога
- Файл событий приложения (Global.asax) - содержит обработчики событий, которые реагируют на глобальные события самого приложения
- Другие компоненты: базы данных, пользовательские элементы управления, отдельные сборки, каскадные таблицы стилей, рисунки, XML-файлы и т.д.
ASP.NET периодически перезапускает приложение в другом домене для освобождения неиспользуемых ресурсов (говорят, что приложение переходит в новый домен ). При этом старый домен будет работать до тех пор, пока не будут обработаны все запросы клиентов, стоящие в очереди. То же самое происходит и при замене разработчиком содержимого страниц и конфигурационных файлов. Среда обнаруживает новые изменения, создает для модифицированного приложения новую сборку и запускает ее в новом домене, выполняя его одновременно со старым немодифицированным. Из-за того, что CLR всегда блокирует файлы сборок при выполнении приложения, перед созданием нового домена она автоматически создает для него копии файлов сборок в каталоге
C:\[Каталог_Windows]\Microsoft.NET\[Версия]\Temporary ASP.NET Files
При создании домена приложение может создавать в нем не один экземпляр объектов приложения, а целый пул, содержащий от 1 до 100 экземпляров, в зависимости от масштабируемости (количества) запросов. Каждый новый запрос от одного и того же клиента может адресоваться к разным экземплярам пула домена.
Файл приложения Global.asax
Файл Global.asax является необязательным для приложения. Но если он присутствует, то должен быть единственным и находиться в корне виртуального каталога приложения. Этот файл включает в себя обработчики событий уровня приложения, которые выполняются автоматически в ответ на происходящие с приложением события. Код обработчиков пишется точно также, как и исполняемый C#-код обычной страницы .aspx и не должен содержать никаких дескрипторов.
Любое приложение является экземпляром класса, наследующего класс HttpApplication. Код файла Global.asax является неявным расширением этого базового класса и будет иметь доступ ко всем его свойствам и методам. В этом файле мы можем заполнить заготовки методов с предопределенными именами, а также создать обработчики на интересующие нас события уровня приложения. Все они должны иметь одинаковую сигнатуру, определенную делегатом
public delegate void System.EventHandler(object sender, System.EventArgs e)
Заготовки методов класса приложения с предопределенными именами
Объект приложения создается автоматически, поэтому мы не можем сами регистрировать некоторые обработчики, присваивая им произвольные имена. Как и в случае с экземпляром класса Page, мы можем использовать только предопределенные имена обработчиков приложения.
Базовый класс HttpApplication имеет ряд событий, которые срабатывают при определенных условиях и в определенной последовательности. Большая часть этих событий связана с запросом. На любое из них мы можем подписаться в методе Application_Start() и создать обработчик с произвольным именем, либо воспользоваться именами по умолчанию Application_ИмяСобытия. В таблице приведены примеры обработчиков событий приложения и сеанса, а также обработчики событий, связанных с запросами:
Демонстрация событий приложения
Приведем пример, иллюстрирующий работу рассмотренных методов уровня приложения.
- Создайте новый пустой проект с помощью команды File/New/Web Site/Empty Web Site
-
Добавьте к проекту командой Website/Add New Item/Web Form новую страницу Default.aspx без файла отделенного кода и модифицируйте ее так
<%@ Page Language="C#" %>
-
Добавьте к проекту файл Web.config командой Website/Add New Item/Web Configuration File с включенной опцией отладки, чтобы его код был таким
<?xml version="1.0"?> <configuration> <system.web> <compilation debug="true"/> </system.web> </configuration>
-
Добавьте к проекту файл Global.asax, выполнив команду Website/Add New Item/Global Application Class, и заполните его следующим кодом
<%@ Application Language="C#" %> <script runat="server"> //************************************************************************ //******************** Обработчики событий приложения ******************** //************************************************************************ void Application_Start(object sender, EventArgs e) { //HttpApplication Application = new HttpApplication(); System.Diagnostics.Debug.WriteLine( "************Application_Start*********"); } void Application_End(object sender, EventArgs e) { System.Diagnostics.Debug.WriteLine( "************Application_End*********"); } void Application_Error(object sender, EventArgs e) { System.Diagnostics.Debug.WriteLine( "************Application_Error*********"); } void Session_Start(object sender, EventArgs e) { System.Diagnostics.Debug.WriteLine( "************Session_Start*********"); } void Session_End(object sender, EventArgs e) { System.Diagnostics.Debug.WriteLine( "************Session_End*********"); } //************************************************************************ //******************** Обработчики событий запроса *********************** //************************************************************************ void Application_BeginRequest(object sender, EventArgs e) { Response.Write("<ol>\n"); Response.Write("<li>Application_BeginRequest\n"); } void Application_AuthenticateRequest(object sender, EventArgs e) { Response.Write("<li>Application_AuthenticateRequest\n"); } void Application_AuthorizeRequest(object sender, EventArgs e) { Response.Write("<li>Application_AuthorizeRequest\n"); } void Application_ResolveRequestCache(object sender, EventArgs e) { Response.Write("<li>Application_ResolveRequestCache\n"); } void Application_AcquireRequestState(object sender, EventArgs e) { Response.Write("<li>Application_AcquireRequestState\n"); } void Application_PreRequestHandlerExecute(object sender, EventArgs e) { Response.Write("<li>Application_PreRequestHandlerExecute\n"); } void Application_PostRequestHandlerExecute(object sender, EventArgs e) { Response.Write("<li>Application_PostRequestHandlerExecute\n"); } void Application_ReleaseRequestState(object sender, EventArgs e) { Response.Write("<li>Application_ReleaseRequestState\n"); } void Application_UpdateRequestCache(object sender, EventArgs e) { Response.Write("<li>Application_UpdateRequestCache\n"); } void Application_EndRequest(object sender, EventArgs e) { Response.Write("<li>Application_EndRequest\n"); Response.Write("</ol>\n"); } </script>
-
Выполните приложение и в окне броузера должен появиться следующий результат
- Application_BeginRequest
- Application_AuthenticateRequest
- Application_AuthorizeRequest
- Application_ResolveRequestCache
- Application_AcquireRequestState
- Application_PreRequestHandlerExecute
- Application_PostRequestHandlerExecute
- Application_ReleaseRequestState
- Application_UpdateRequestCache
- Application_EndRequest
- В панели задач щелкните дважды на иконке тестового сервера
- Остановите тестовый сервер щелчком на кнопке Stop
- Откройте (если его не видно) окно Output оболочки командой View/Output и обратите внимание, что в нем присутствует, в том числе, информация, выдаваемая обработчиками приложения и сеанса, которая будет примерно такой
************Application_Start********* 'WebDev.WebServer.EXE' (Managed): Loaded 'C:\WINNT\assembly\GAC_MSIL\System.Web.Mobile\2.0.0.0__b03f5f7f11d50a3a\System.Web.Mobile.dll', No symbols loaded. 'WebDev.WebServer.EXE' (Managed): Loaded 'C:\WINNT\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\website5x\e0138830\7001bf15\ App_Web_ayudlfun.dll', Symbols loaded. ************Session_Start********* 'WebDev.WebServer.EXE' (Managed): Loaded 'C:\WINNT\assembly\GAC_MSIL\System.Web.RegularExpressions\2.0.0.0__b03f5f7f11d50a3a\System.Web.RegularExpressions.dll', No symbols loaded. ************Session_End********* ************Application_End********* The program '[1800] WebDev.WebServer.EXE: Managed' has exited with code 0 (0x0). The program '[820] IEXPLORE.EXE: Script program' has exited with code 0 (0x0).
Демонстрация перехвата необработанного события
- Добавьте к проекту новую страницу Default2.aspx с файлом отделенного кода и назначьте ее стартовой командой Set As Start Page
-
Заполните в застраничном файле обработчик Page_Load() кодом деления на ноль
protected void Page_Load(object sender, EventArgs e) { int a=0, b=1; int x = b / a; }
-
Откройте файл Global.asax, очистите его и скорректируйте так
<%@ Application Language="C#" %> <script runat="server"> void Application_Error(object sender, EventArgs e) { Response.Write("<h1>"); Response.Write("Произошла какая-то ошибка</h1><hr />"); Response.Write(Server.GetLastError().Message.ToString()); Response.Write("<hr />" + Server.GetLastError().ToString()); Server.ClearError(); } </script>
- Установите в редакторе оболочки страницу Default2.aspx текущей и через контекстное меню выполните для нее команду View in Browser
Html-вывод страницы будет таким
В таком объеме информации трудно разобраться и поэтому обработчик Application_Error() программисты используют только в крайнем случае.