-
Итак, IIS передает ход ISAPI Application aspnet_isapi.dll, а тот, в свою очередь, перенаправляет запрос процессу
w3wp.exe (для Windows 2003) или aspnet_wp.exe (если у вас Windows XP), которые и являются движками, для выполнения ASP.NET
прилолжений.
-
Здесь картина опять повторяется. Сначала ASP.NET по очереди вызывает все модули (HttpModules),
зарегистрированные для web-приложения. Для этого просматриваются секции <httpModules> всех конфигурационных файлов,
начиная от корневого machine.config и заканчивая web.config файлом, ближе всех расположенным к вызываемой странице.
Именно таким образом вызываются системные модули типа Session (поддерживающий понятие "сессия") или FormsAuthentication
(выполняющий аутентификацию пользователей).
Вот пример из корневого web.config файла, расположенного в каталоге "<windows>\Microsoft.NET\Framework\<version>\config\":
<configuration>
<system.web>
<httpModules>
<add name="OutputCache" type="System.Web.Caching.OutputCacheModule"/>
<add name="Session" type="System.Web.SessionState.SessionStateModule"/>
 . . .
</httpModules>
</system.web>
</configuration>
|
-
И, наконец-то, ASP.NET ищет тот HttpHandler, который, собственно, и обработает запрос. Для этого опять прсматриваются все
конфигурационные файлы, в которых можно сопоставлять модули с запрашиваемыми типами файлов, а так же с типами запросов. Например,
можно указать, что HttpHandler "MyAssembly.MyHandler" нужно вызывать, если идет обращение типа "GET" к файлам с расширением .aspx:
<configuration>
<system.web>
<httpHandlers>
<add path=".aspx" verb="GET" type="MyAssembly.MyHandler"/>
. . .
</httpHandlers>
</system.web>
</configuration>
|
Если пользовательских обработчиков не найдено, в корневом web.config прописаны обработчики по умолчанию, например для .aspx
страниц вызывается System.Web.DefaultHttpHandler.
-
Стандартный ASP.NET обработчик передает управление вашей странице, унаследованной от класса Page. Сформированный
страницей ответ (объект HttpResponse) передается по цепочке обратно и, в конце концов, отсылается браузеру,
приславшему запрос.

Уф, мои поздравления тем, кто набрался терпения и таки добрался до этого места. Теперь мы знаем вполне достаточно, чтобы легко
понять все остальные способы перенаправления urls.
Если вы еще помните :), мы собирались разобраться, как реализовать url rewriting своими руками. Все сводится к использованию
метода HttpContext.RewritePath. При помощи параметра
string filePath можно указать,
какая страница нашего веб-приложения будет выполнятся на самом деле. RewritePath содержит несколько
переопределенных вариантов, которые позволяют изменить такие параметры запроса как query string или path info.
Прим. Для ASP.NET, Path info - это та часть url, которая может находиться после расширения страницы до query string.
Например в Url:
http://www.sport.news.ru/tennis/news.aspx/topnews?type=12&page=2
path info - "/topnews". С точки зрения поисковиков path info - это просто часть Url, так что для них Urls:
- http://www.sport.news.ru/tennis/news.aspx/topnews
- http://www.sport.news.ru/tennis/news.aspx/raiting
- http://www.sport.news.ru/tennis/news.aspx/comments
являются разными страницами. Для ASP.NET это будет одна и та же страница с разными значениями свойства
PathInfo в объекте HttpRequest.
|
Итак, что для того чтобы перенаправить один url на другой, мы должны:
-
Создать и зарегистрировать в нашем приложении HttpModule.
-
Добавить в этом модуле свой обработчик к событию приложения, в котором мы будем выполнять перенаправление
(если вы используете Forms Authentication, лучше выбрать AuthorizeRequest, если Windows Authentication -
подойдет и BeginRequest).
-
В обработчике выполнить перенаправление Url при помощи вызова RewritePath.
-
Разобраться с проблемой, связанная с аттрибутом "action" тега <form>.
В нем сохраняется url текущей страницы, именно его вызовет браузер во время post-back. Уже догадались, что произойдет?
Допустим, мы вызвали страницу http://news.ru/tennis/raiting/ и перенаправили его на raiting.aspx?section=12.
Во время отработки страницы, в аттрибут "action" будет занесено именно "raiting.aspx". После того как страница отдастся
браузеру и пользователь нажмет какую-нибудь кнопку, post-back пойдет именно на "raiting.aspx" (и этот url высветится в строке
запроса браузера), а вовсе не http://news.ru/tennis/raiting/, как мы хотели.
Так что нам прийдется подменять значение этого аттрибута.
Вот как это может выглядеть:
// UrlRewriterModule.cs file
public class UrlRewriterModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.AuthorizeRequest += new EventHandler(OnAuthorizeRequest);
}
public void Dispose()
{
}
void OnAuthorizeRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
String oldUrl = app.Request.RawUrl;
String newUrl = ...;
HttpContext.Current.RewritePath(newUrl);
}
}
// web.config file
<configuration>
<system.web>
<httpModules>
<add name="UrlRewriter" type="MyAssembly.UrlRewriterModule"/>
 . . .
|
Осталось корректно обработать аттрибут "action". Раньше, в ASP.NET 1.1, разработчикам приходилось переопределять элемент
управления Form, а это значит - менять код всех страниц, заменяя на них стандартный <asp:form>. Кроме того, иногда
это приводило к проблемам в Visual Studio WYSIWYG designer.

В ASP.NET 2.0 все можно сделать проще, благодаря использованию ASP.NET 2.0 CSS Control Adapters. Эта технология позволяет
связывать ваши классы с какими-то типами элементов управления. Связанные классы могут изменять html, генерируемый элементами
управления в процессе рендеринга. Более подробно я описывал эту технологию в предыдущей статье
"
Как совместить заказной дизайн и ASP.NET web-сайты".
То есть, мы создаем control adapter для класса HtmlForm, переопределяем в нем метод Render и выполняем rendering используя собственный класс,
унаследованный от HtmlTextWriter и отличающися от него только алгоритмом добавления аттрибута "action".
Чтобы упростить себе жизнь, воспользуемся одним малоизвестным трюком - если аттрибут "action" вообще не указан - браузер будет использовать для
post-back url, указанный в строке запроса, что нас вполне устраивает.
Итак, пишем код для form control adapter:
// HtmlFormControlAdapter.cs file
public class HtmlFormControlAdapter : ControlAdapter
{
protected override void Render(HtmlTextWriter writer)
{
base.Render(new RewriteFormHtmlTextWriter(writer));
}
}
// RewriteFormHtmlTextWriter.cs file
public class RewriteFormHtmlTextWriter : HtmlTextWriter
{
public RewriteFormHtmlTextWriter(HtmlTextWriter writer) : base(writer)
{
this.InnerWriter = writer.InnerWriter;
}
public RewriteFormHtmlTextWriter(System.IO.TextWriter writer) : base(writer)
{
this.InnerWriter = writer;
}
public override void WriteAttribute(string name, string value, bool fEncode)
{
if (name == "action")
{
value = String.Empty;
}
base.WriteAttribute(name, value, fEncode);
}
}
|
Теперь осталось связать наш control adapter с элементом HtmlForm. Создаем класс Form.browser с таким вот содержимым:
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter adapterType="MyAssembly.HtmlFormControlAdapter, MyAssembly" controlType="System.Web.UI.HtmlControls.HtmlForm" />
</controlAdapters>
</browser>
</browsers>
|
и помещаем его в служебную папку App_Browsers нашего приложения.
Вуаля! Теперь значение аттрибута "action" всегда пустое и post-back страниц при любой реализации rewriting должен работать нормально.