Опубликован: 07.05.2010 | Доступ: свободный | Студентов: 1678 / 62 | Оценка: 4.56 / 4.06 | Длительность: 34:11:00
Лекция 8:

Программирование уровня приложения ASP.NET

< Лекция 7 || Лекция 8 || Лекция 9 >
Аннотация: Файл приложения Global.asax. Заготовки методов класса приложения с предопределенными именами. Демонстрация событий приложения. Демонстрация перехвата необработанного события.

Файлы к лекции Вы можете скачать здесь

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

Исполняемое средой ASP.NET приложение называется доменом (по аналогии с процессом при исполнении приложения локального стола). В отличие от локальных приложений, конечный пользователь никогда не запускает приложение ASP.NET напрямую. Он запускает броузер на своем локальном компьютере и запрашивает определенный URL. Этот запрос получет Web-сервер и передает его среде исполнения ASP.NET (рабочему процессу), которая выделяет в памяти домен для виртуального каталога и загружает в него код адресуемой страницы. Таким образом, домен приложения создается рабочим процессом при первом запросе любой страницы или Web-службы виртуального каталога.

Web-страницы и Web-службы одного виртуального каталога выполняются в одном и том же домене. Содержимое другого виртуального каталога выполняется в своем домене. Выполнение приложений из разных виртуальных каталогов в отдельных изолированных доменах гарантирует, что одно приложение не сможет оказывать влияние на работу другого, в том числе видеть его данные, хранящиеся в оперативной памяти. За этим строго следит общеязыковая среда выполнения CLR.

Все Web-страницы или Web-службы совместно используют одни и те же ресурсы, которые недоступны другим приложениям. Конфигурационные настройки среды исполнения, помещенные в файл Web.config виртуального каталога приложения, действуют только в пределах этого приложения. Страницы, требующие еще более индивидуальных настроек, могут быть помещены в подкаталоги со своими файлами Web.config.

Приложение может состоять из следующих компонентов:

  1. Web-страницы (файлы .aspx) - основные рабочие единицы любого приложения
  2. Web-службы (файлы .asmx) - выполняют полезную работу для сторонних приложений
  3. Файлы отделенного кода (.cs) - содержат исполнимый код для программного управления объектами, определяемыми в интерфейсной части страницы
  4. Конфигурационные файлы (Web.config) - содержат настройки среды исполнения (рабочего процесса) как для всего приложения в целом, так и для групп страниц, расположенных в подкаталогах виртуального каталога
  5. Файл событий приложения (Global.asax) - содержит обработчики событий, которые реагируют на глобальные события самого приложения
  6. Другие компоненты: базы данных, пользовательские элементы управления, отдельные сборки, каскадные таблицы стилей, рисунки, 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_ИмяСобытия. В таблице приведены примеры обработчиков событий приложения и сеанса, а также обработчики событий, связанных с запросами:

Некоторые обработчики уровня приложения
Обработчик Описание
Обработчики событий приложения и сеанса
Application_Start() Этот метод вызывается тогда, когда впервые запускается приложение и создается домен. В этом обработчике удобно инициализировать такие данные, как деревья навигации, общие счетчики и др.
Application_End() Вызывается сразу после завершения работы приложения. Приложение может завершить работу вследствии перезапуска IIS или перехода в новый домен из-за обновления файлов виртуального каталога
Application_Error() Вызывается всякий раз, когда в приложении возникает необработанное событие
Session_Start() Вызывается всякий раз, когда в приложении начинается новый сеанс. Удобен для инициализации информации, специфичной для конечного пользователя
Session_End() Вызывается всякий раз при завершении сеанса. Сеанс завершается, когда мы явно освобождаем его в коде, или если сеанс простоял заданное время (обычно 20 минут), не получив ни одного запроса. Используется для очистки любых связанных данных
Обработчики событий, связанных с запросами
Application_BeginRequest() Вызывается в начале каждого запроса, включая запросы на файлы, не являющиеся Web-формами (например, Web-службы)
Application_AuthenticateRequest() Вызывается до начала аутентификации (распознавания пользователя). Сюда можно поместить собственную логику аутентификации
Application_AuthorizeRequest() Вызывается после выполнения аутентификации для назначения специальных прав
Application_ResolveRequestCache() Используется вместе с кэшированием выходных данных
Application_AcquireRequestState() Срабатывает после извлечения из запроса информации о пользователе перед сохранением ее в коллекции сеанса
Application_PreRequestHandlerExecute() Вызывается перед тем, как будет выполнен запрос и сгенерируется HTML-код обработчиками страницы
Application_PostRequestHandlerExecute() Вызывается после обработки запроса
Application_ReleaseRequestState() Вызывается тогда, когда информация сеанса сериализуется из коллекции Session, чтобы стать доступной в следующем запросе
Application_UpdateRequestCache() Вызывается перед добавлением информации в кэш выходных данных, если он был разрешен
Application_EndRequest() Вызывается в конце запроса и используется для размещения кода очистки

Демонстрация событий приложения

Приведем пример, иллюстрирующий работу рассмотренных методов уровня приложения.

  • Создайте новый пустой проект с помощью команды 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>
  • Выполните приложение и в окне броузера должен появиться следующий результат
    1. Application_BeginRequest
    2. Application_AuthenticateRequest
    3. Application_AuthorizeRequest
    4. Application_ResolveRequestCache
    5. Application_AcquireRequestState
    6. Application_PreRequestHandlerExecute
    7. Application_PostRequestHandlerExecute
    8. Application_ReleaseRequestState
    9. Application_UpdateRequestCache
    10. 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() программисты используют только в крайнем случае.

< Лекция 7 || Лекция 8 || Лекция 9 >