HttpModule — это сборка, реализующая интерфейс IHttpModule и обрабатывающая события. ASP.NET включает набор сборок HttpModule, которые могут использоваться в приложениях пользователей. Например, SessionStateModule предоставляется ASP.NET для поставки в приложение служб состояния сеанса. Пользовательские обработчики HttpModule могут быть созданы в качестве ответа на событие ASP.NET или событие пользователя.
Общая процедура написания обработчика HttpModule следующая:
• Реализация интерфейса IHttpModule.
• Обработка метода Init и регистрация необходимых событий.
• Обработка событий.
• Реализация (при необходимости) метода Dispose, если требуется выполнить очистку.
• Регистрация модуля в файле Web.config.
HTTP Module включается в процесс обработки запроса пользователя после создания объекта HTTP Application и перед созданием HTTP Handle, так что HTTP Module позволяет обработать следующие события объекта HTTP Application:
• BeginRequest
• AuthenticateRequest
• PostAuthenticateRequest
• AuthorizeRequest
• PostAuthorizeRequest
• ResolveRequestCache
• PostResolveRequestCache
• PostMapRequestHandler
• AcquireRequestState
• PostAcquireRequestState
• PreRequestHandlerExecute
• PostRequestHandlerExecute
• ReleaseRequestState
• PostReleaseRequestState
• UpdateRequestCache
• PostUpdateRequestCache
• EndRequest
Подключение обработчиков событий выполняется в методе Init класса HTTPModule.
В своем примере мне необходимо подключить обработчик на 2 события ReleaseRequestState и PreSendRequestHeaders для того что бы созданные обработчики вызывался перед обработчикам созданным библиотекой для сжатия HTML-документов (если такая так же подключена к проекту).
/// <summary>
/// Подключение обработчиков событий
/// </summary>
public void Init(HttpApplication context)
{
//Подключаем обработчик на событие ReleaseRequestState
context.ReleaseRequestState += new EventHandler(this.context_Clear);
//Подключаем обработчик на событие PreSendRequestHeaders
context.PreSendRequestHeaders += new EventHandler(this.context_Clear);
//Два обработчика необходимы для совместимости с библиотеками сжатия HTML-документов
}
Сам обработчик будет иметь следующий вид:
/// <summary>
/// Обработчик события PostRequestHandlerExecute
/// </summary>
void context_Clear(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender; //Получение HTTP Application
//Получаем имя файла который обрабатывается
string realPath = app.Request.Path.Remove(0, app.Request.ApplicationPath.Length + 1);
//Проверяем не является ли он ссылкой на ресурс сборки
if (realPath == "WebResource.axd")
return; //Проверяем тип содержимого
if (app.Response.ContentType == "text/html")
//Устанавливаем фильтр-обработчик
app.Context.Response.Filter = new HTMLClearer(app.Context.Response.Filter);
}
Фильтр-обработчик - это самое главное. Он позволяет изменять содержимое объекта Response. А дополнительные проверки необходимы, чтобы исключить обработку ресурсов сборок и документов, тип которых отличен от text/html (в документах другого типа нет необходимости убирать лишние символы).
Теперь уделим внимание обработчику содержимого Response.
Это класс, являющийся наследником System.IO.Stream. В его реализации нам интересен только один метод - это метод Write:
/// <summary>
/// Обрабатываем данные поступающие в Response
/// </summary>
public override void Write(byte[] buffer, int offset, int count)
{
//Преобразовываем массив байт в строку
string s = System.Text.Encoding.UTF8.GetString(buffer);
//Используя регулярные выражения убираем все ненужные символы
s = Regex.Replace(s,
">(\r\n){0,10} {0,20}\t{0,10}(\r\n){0,10}\t{0,10}(\r\n){0,10} {0,20}(\r\n){0,10} {0,20}<", ">
<", RegexOptions.Compiled);
s = Regex.Replace(s,
";(\r\n){0,10} {0,20}\t{0,10}(\r\n){0,10}\t{0,10}", ";", RegexOptions.Compiled);
s = Regex.Replace(s,
"{(\r\n){0,10} {0,20}\t{0,10}(\r\n){0,10}\t{0,10}", "{", RegexOptions.Compiled);
s = Regex.Replace(s, ">(\r\n){0,10}\t{0,10}<", "><", RegexOptions.Compiled);
s = Regex.Replace(s, ">\r{0,10}\t{0,10}<", "><", RegexOptions.Compiled);
//Получивщуюся строку преобразовываем обратно в byte
byte[] outdata = System.Text.Encoding.UTF8.GetBytes(s);
//Записываем ее в Response
_HTML.Write(outdata, 0, outdata.Length);
}
А также конструктор класса:
public HTMLClearer(System.IO.Stream HTML)
{ _HTML = HTML; }
Для демонстрации примера использования HTTP Module и обработчика содержимого объекта HTTP Response создадим проект Class Library и назовем его - HTMLClearer. В этом проекте следует создать файл HTMLClearer.cs, содержащей следующий текст:
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Text.RegularExpressions;
namespace HTMLClearer
{
public class HTMLClearer : System.IO.Stream
{
System.IO.Stream _HTML;
public HTMLClearer(System.IO.Stream HTML)
{ _HTML = HTML; } #region Стандартные методы и свойства
public override bool CanRead
{ get { return false; } }
public override bool CanSeek
{ get { return false; } }
public override bool CanWrite
{ get { return true; } }
public override long Length
{ get { return _HTML.Length; } }
public override long Position
{
get { return _HTML.Position ; }
set { _HTML.Position = value; }
}
public override long Seek(long offset, System.IO.SeekOrigin origin)
{ return _HTML.Seek(offset, origin); }
public override void SetLength(long value)
{ _HTML.SetLength(value); }
public override void Flush()
{ _HTML.Flush(); }
public override int Read(byte[] buffer, int offset, int count)
{ return _HTML.Read(buffer, offset, count); }
#endregion
/// <summary>
/// Обрабатываем данные поступающие в Response
/// </summary>
public override void Write(byte[] buffer, int offset, int count)
{
//Преобразовываем массив байт в строку
string s = System.Text.Encoding.UTF8.GetString(buffer);
//Используя регулярные выражения убираем все ненужные символы
s = Regex.Replace(s, ">(\r\n){0,10} {0,20}\t{0,10}(\r\n){0,10}\t{0,10}(\r\n)
{0,10} {0,20}(\r\n){0,10} {0,20}<", "><", RegexOptions.Compiled);
s = Regex.Replace(s, ";(\r\n){0,10} {0,20}\t{0,10}(\r\n){0,10}\t{0,10}", ";",
RegexOptions.Compiled);
s = Regex.Replace(s, "{(\r\n){0,10} {0,20}\t{0,10}(\r\n){0,10}\t{0,10}", "{",
RegexOptions.Compiled);
s = Regex.Replace(s, ">(\r\n){0,10}\t{0,10}<", "><", RegexOptions.Compiled);
s = Regex.Replace(s, ">\r{0,10}\t{0,10}<", "><", RegexOptions.Compiled);
//Получивщуюся строку преобразовываем обратно в byte
byte[] outdata = System.Text.Encoding.UTF8.GetBytes(s);
//Записываем ее в Response
_HTML.Write(outdata, 0, outdata.Length);
}
}
public class HTTPModule_Clearer : IHttpModule
{
#region IHttpModule Members
public void Dispose()
{
}
/// <summary>
/// Подключение обработчиков событий
/// </summary>
public void Init(HttpApplication context)
{
//Подключаем обработчик на событие ReleaseRequestState
context.ReleaseRequestState += new EventHandler(this.context_Clear);
//Подключаем обработчик на событие PreSendRequestHeaders
context.PreSendRequestHeaders += new EventHandler(this.context_Clear);
//Два обработчика необходимы для совместимости с библиотеками сжатия HTML-документов
}
/// <summary>
/// Обработчик события PostRequestHandlerExecute
/// </summary>
void context_Clear(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender; //Получение HTTP Application
string realPath = app.Request.Path.Remove(0, app.Request.ApplicationPath.Length + 1);
//Получаем имя файла который обрабатывается
if (realPath == "WebResource.axd") //Проверяем не является ли он ссылкой на ресурс сборки
return;
if (app.Response.ContentType == "text/html")//Проверяем тип содержимого
app.Context.Response.Filter = new HTMLClearer(app.Context.Response.Filter);
//Устанавливаем фильтр обработчик
}
#endregion
}
}
После всех этих манипуляций компилируем проект, и получившуюся библиотеку через Add Reference подключаем к Веб-сайту.
Теперь нам необходимо подключить HTTP Module к общему потоку обработки запросов (если в проекте используется модуль сжатия HTML-документов, то он должен быть добавлен после модуля HTMLClearer). Для этого в файле web.config необходимо сделать некоторые изменения, а именно в раздел system.web добавить ссылку на модуль:
<httpsModules>
<add name="HTTPModule_Clearer" type="HTMLClearer.HTTPModule_Clearer, HTMLClearer"/>
</httpsModules>Общий вид тега <httpsModules> взятый из MSDN выглядит так:
<httpsModules>
<add type="classname,assemblyname" name="modulename"/>
<remove name="modulename"/>
<clear/>
</httpsModules>
Подтег Описание
<add> Добавляет в приложение класс HttpModule.
Обратите внимание, что в случае сочетания команда-путь, идентичного уже указанному ранее (например, в файле Web.config родительской папки), второй вызов <add> переопределяет предыдущее значение.
<remove> Удаляет из приложения класс HttpModule.
<clear>
Удаляет из приложения все сопоставления HttpModule.
При использовании данного модуля размер HTML-страничек, отправляемых пользователю, уменьшается примерно на 10%, что не может не сказаться на трафике, как пользователя, так и сервера.
P.S.
Использование HTTP Module позволяет также вносить изменения в отправляемый пользователю ответ (например, если есть необходимость добавить к странице Header или Footer).
Также, дописав метод Write, можно сохранять определенные части страницы или страницы целиком в базу данных или в файл.