Два перехватчика: HttpModule и HttpHandlers

ОГЛАВЛЕНИЕ

Часто необходимо реализовать логику предварительной обработки прежде, чем запрос достиг ресурсов IIS. Например, надо применить механизм защиты, замену URL, отфильтровать что-то в запросе и т. д. ASP.NET предоставляет два типа перехвата - HttpModule и HttpHandler.  Данная статья описывает их.

•    Скачать исходники и демо - 12.02 Кб

Задача

То и дело необходимо вставить какую-то логику перед запросом страницы. Часто используемой логикой предварительной обработки являются счетчики статистики, замена URL, аутентификация / авторизация и многие другие. Это можно делать в отделенном коде, но это приводит к сложному и запутанному коду. Отделенный код не решит задачу, потому что в ряде реализаций вроде авторизации логика должна выполняться до достижения ею ресурса. ASP.NET предоставляет два способа вставки логики в канал запроса - HttpHandlers и HttpModules.

HttpHandler – препроцессор на базе расширения

HttpHandler помогает вставить логику предварительной обработки на базе расширения запрошенного имени файла. Когда запрашивается страница, HttpHandler выполняется на базе расширения имени файла и на базе глагола. Рисунок ниже показывает, как разные обработчики увязаны с расширением файла. Можно увязать один обработчик с несколькими расширениями файлов. Например, когда любой клиент запрашивает файл с расширением ‘GIF’ и ‘JPEG’, выполняется логика предварительной обработки handler3.

HttpModule – препроцессор на базе события

HttpModule – метод вставки логики предварительной обработки перед запросом любого ресурса на базе события. Когда любой клиент отправляет запрос на ресурс, канал запроса порождает много событий, как показано на рисунке ниже:

Ниже дано подробное объяснение событий.
•    BeginRequest: Запрос был запущен. Если надо сделать что-то в начале запроса (например, отобразить рекламные баннеры вверху каждой страницы), синхронизируйте это событие.
•    AuthenticateRequest: Если надо встроить пользовательскую схему аутентификации (например, найти пользователя в базе данных для проверки пароля), постройте модуль, синхронизирующий это событие и аутентифицирующий пользователя нужным образом.
•    AuthorizeRequest: Это событие используется внутри для реализации механизмов авторизации (например, для хранения списков контроля доступа (ACL) в базе данных, а не в файловой системе). Хотя можно переопределить данное событие, для этого мало веских причин.
•    PreRequestHandlerExecute: Это событие происходит перед выполнением обработчика HTTP.
•    PostRequestHandlerExecute: Это событие происходит после выполнения обработчика HTTP.
•    EndRequest: Запрос завершился. Можно построить модуль отладки, собирающий информацию в течение всего запроса и затем выводящий информацию на страницу.

Можно зарегистрировать эти события в HttpModules. Когда выполняется канал запроса, в зависимости от зарегистрированного события, обрабатывается логика из модулей.

Общая картина обработчика и модулей

Изучив основы, пора рассмотреть определение Microsoft для обработчика и модулей, чтобы получить общую картину.

Ссылка: Информация: Обзор модулей HTTP и обработчиков HTTP ASP.NET

“Модули вызываются до и после выполнения обработчика. Модули позволяют разработчикам перехватить, участвовать в или изменить каждый отдельный запрос. Обработчики применяются для обработки отдельных запросов конечной точки. Обработчики позволяют каркасу ASP.NET обрабатывать отдельные HTTP URL или группы расширений URL внутри приложения. В отличие от модулей, только один обработчик используется для обработки запроса”.


Шаги реализации HttpHandlers

Шаг 1

HttpHandlers являются классами, реализующими логику предварительной обработки. Поэтому сначала надо создать проект класса и сослаться на пространство имен System.Web и реализовать интерфейс IHttpHandler, как показано во фрагменте кода ниже. Интерфейс IHttpHandler имеет два метода, требующих реализации; один – ProcessRequest, а второй - IsResuable. В методе ProcessRequest URL вводится в файл и отображается в браузере. Был обработан объект ответа контекста, чтобы отправить вывод браузеру.

using System;
using System.Web;
using System.IO;
namespace MyPipeLine
{
public class clsMyHandler : IHttpHandler
{
public void ProcessRequest(System.Web.HttpContext context)
{
context.Response.Write("The page request is " + context.Request.RawUrl.ToString());
StreamWriter sw = new StreamWriter(@"C:\requestLog.txt",true);
sw.WriteLine("Page requested at " + DateTime.Now.ToString() +
            context.Request.RawUrl); sw.Close();
}
public bool IsReusable
{
get
{
return true;
}
}
}

Шаг 2

На шаге 2 надо сделать запись тега HttpHandlers. В теге надо указать, какой вид запрошенного расширения вызовет класс.

<system.web>
<httpHandlers>
<add verb="*" path="*.Shiv,*.Koirala" type="MyPipeLine.clsMyHandler, MyPipeLine"/>
</httpHandlers>
</system.web>

Сделав все, запросите имя страницы с расширением ‘Shiv’ и увидите показанный ниже вывод. Когда IIS видит, что запрос предназначен для расширения страницы ‘.shiv’, он вызывает логику предварительной обработки класса clsMyHandler.

Шаги реализации HttpModule

Шаг 1

Как сказано ранее, HttpModule является препроцессором события. Поэтому сначала надо реализовать IHttpModule и зарегистрировать необходимые события, на которые этот модуль должен подписаться. В примере зарегистрировались в событиях BeginRequest и EndRequest. В этих событиях запись заносится в файл журнала.

public class clsMyModule : IHttpModule
{
public clsMyModule()
{}
public void Init(HttpApplication objApplication)
{
// зарегистрировать обработчик события канала
objApplication.BeginRequest += new EventHandler(this.context_BeginRequest);
objApplication.EndRequest += new EventHandler(this.context_EndRequest);
}
public void Dispose()
{
}
public void context_EndRequest(object sender, EventArgs e)
{
StreamWriter sw = new StreamWriter(@"C:\requestLog.txt",true);
sw.WriteLine("End Request called at " + DateTime.Now.ToString()); sw.Close();
}
public void context_BeginRequest(object sender, EventArgs e)
{
StreamWriter sw = new StreamWriter(@"C:\requestLog.txt",true);
sw.WriteLine("Begin request called at " + DateTime.Now.ToString()); sw.Close();
}
}

Шаг 2

Надо внести эти записи модуля в тег HttpModule, как показано во фрагменте кода ниже:

<httpModules>
<add name="clsMyModule" type="MyPipeLine.clsMyModule, MyPipeLine"/>
</httpModules>

Итоговый вывод

При выполнении кода в RequestLog.txt должно появиться нечто вроде следующего. Вышеприведенный пример непрактичен, но помогает понять основы.

Begin request called at 11/12/2008 6:32:00 PM
End Request called at 11/12/2008 6:32:00 PM
Begin request called at 11/12/2008 6:32:03 PM
End Request called at 11/12/2008 6:32:03 PM
Begin request called at 11/12/2008 6:32:06 PM
End Request called at 11/12/2008 6:32:06 PM
Begin request called at 11/12/2008 8:36:04 PM
End Request called at 11/12/2008 8:36:04 PM
Begin request called at 11/12/2008 8:37:06 PM
End Request called at 11/12/2008 8:37:06 PM
Begin request called at 11/12/2008 8:37:09 PM
End Request called at 11/12/2008 8:37:09 PM
Begin request called at 11/12/2008 8:37:38 PM
Page requested at 11/12/2008 8:37:38 PM/WebSiteHandlerDemo/Articles.shiv
End Request called at 11/12/2008 8:37:38 PM