Виртуальный каталог, который мы создаем в самом начале разработки сайта, при исполнении страниц ассоциируется с отдельным приложением. Приложение является отдельной программной единицей, изолированной при исполнении от страниц других виртуальных каталогов. Все, что находится в виртуальном каталоге, относится к приложению.
Исполняемое средой ASP.NET приложение называется доменом (по аналогии с процессом при исполнении приложения локального стола). В отличие от локальных приложений, конечный пользователь никогда не запускает приложение ASP.NET напрямую. Он запускает броузер на своем локальном компьютере и запрашивает определенный URL. Этот запрос получет Web-сервер и передает его среде исполнения ASP.NET (рабочему процессу), которая выделяет в памяти домен для виртуального каталога и загружает в него код адресуемой страницы. Таким образом, домен приложения создается рабочим процессом при первом запросе любой страницы или Web-службы виртуального каталога.
Web-страницы и Web-службы одного виртуального каталога выполняются в одном и том же домене. Содержимое другого виртуального каталога выполняется в своем домене. Выполнение приложений из разных виртуальных каталогов в отдельных изолированных доменах гарантирует, что одно приложение не сможет оказывать влияние на работу другого, в том числе видеть его данные, хранящиеся в оперативной памяти. За этим строго следит общеязыковая среда выполнения CLR.
Все Web-страницы или Web-службы совместно используют одни и те же ресурсы, которые недоступны другим приложениям. Конфигурационные настройки среды исполнения, помещенные в файл Web.config виртуального каталога приложения, действуют только в пределах этого приложения. Страницы, требующие еще более индивидуальных настроек, могут быть помещены в подкаталоги со своими файлами Web.config.
Приложение может состоять из следующих компонентов:
ASP.NET периодически перезапускает приложение в другом домене для освобождения неиспользуемых ресурсов (говорят, что приложение переходит в новый домен ). При этом старый домен будет работать до тех пор, пока не будут обработаны все запросы клиентов, стоящие в очереди. То же самое происходит и при замене разработчиком содержимого страниц и конфигурационных файлов. Среда обнаруживает новые изменения, создает для модифицированного приложения новую сборку и запускает ее в новом домене, выполняя его одновременно со старым немодифицированным. Из-за того, что CLR всегда блокирует файлы сборок при выполнении приложения, перед созданием нового домена она автоматически создает для него копии файлов сборок в каталоге
C:\[Каталог_Windows]\Microsoft.NET\[Версия]\Temporary ASP.NET Files
При создании домена приложение может создавать в нем не один экземпляр объектов приложения, а целый пул, содержащий от 1 до 100 экземпляров, в зависимости от масштабируемости (количества) запросов. Каждый новый запрос от одного и того же клиента может адресоваться к разным экземплярам пула домена.
Файл Global.asax является необязательным для приложения. Но если он присутствует, то должен быть единственным и находиться в корне виртуального каталога приложения. Этот файл включает в себя обработчики событий уровня приложения, которые выполняются автоматически в ответ на происходящие с приложением события. Код обработчиков пишется точно также, как и исполняемый C#-код обычной страницы .aspx и не должен содержать никаких дескрипторов.
Любое приложение является экземпляром класса, наследующего класс HttpApplication. Код файла Global.asax является неявным расширением этого базового класса и будет иметь доступ ко всем его свойствам и методам. В этом файле мы можем заполнить заготовки методов с предопределенными именами, а также создать обработчики на интересующие нас события уровня приложения. Все они должны иметь одинаковую сигнатуру, определенную делегатом
public delegate void System.EventHandler(object sender, System.EventArgs e)
Объект приложения создается автоматически, поэтому мы не можем сами регистрировать некоторые обработчики, присваивая им произвольные имена. Как и в случае с экземпляром класса Page, мы можем использовать только предопределенные имена обработчиков приложения.
Базовый класс HttpApplication имеет ряд событий, которые срабатывают при определенных условиях и в определенной последовательности. Большая часть этих событий связана с запросом. На любое из них мы можем подписаться в методе Application_Start() и создать обработчик с произвольным именем, либо воспользоваться именами по умолчанию Application_ИмяСобытия. В таблице приведены примеры обработчиков событий приложения и сеанса, а также обработчики событий, связанных с запросами:
Приведем пример, иллюстрирующий работу рассмотренных методов уровня приложения.
<%@ Page Language="C#" %>
<?xml version="1.0"?> <configuration> <system.web> <compilation debug="true"/> </system.web> </configuration>
<%@ 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_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).
protected void Page_Load(object sender, EventArgs e) { int a=0, b=1; int x = b / a; }
<%@ 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>
Html-вывод страницы будет таким
В таком объеме информации трудно разобраться и поэтому обработчик Application_Error() программисты используют только в крайнем случае.