Меняем URL’ы на лету

Одним из наиболее слабоосвещённых – но потенциально полезных – методов .NET Framework в части, касающейся ASP.NET, является метод класса HttpContext RewritePath. Этот метод используется ASP.NET для получения сессионного идентификатора из URL’a, при задействованном состоянии сессии без использования куки. Метод RewritePath также может быть использован и для подмены URL’a внутри приложения. Для демонстрации предположим, что у нас есть следующий ASPX-файл, который мы назовём RewritePath.aspx:

<html>
    <
body>
    <
h2><asp:Label ID="Output" RunAt="server" /></h2>
    </
body>
    </
html>

    <
script language="C#" runat="server">
   
void Page_Load (Object sender, EventArgs e)
    {
   
string id = Request.QueryString["ID"];
    if (
id != null && id != String.Empty) {
    switch (
id) {
    case
"1":
   
Output.Text = "Give me chastity and " +
   
"continence, but not yet.";
    break;

    case
"2":
   
Output.Text = "A programmer is a device " +
   
"for turning coffee into code.";
    break;

    case
"3":
   
Output.Text = "Blessed is the man who, " +
   
"having nothing to say, abstains from " +
   
"giving wordy evidence of the fact.";
    break;
    }}}
   
</script>

Если эту страницу поместить в виртуальный каталог Foo, то следующие три URL’a отобразят три разных утверждения:

http://.../foo/rewritepath.aspx?id=1
http://.../foo/rewritepath.aspx?id=2
http://.../foo/rewritepath.aspx?id=3

А теперь представьте, что вы хотите предоставить вашим пользователям получать эти утверждения с использованием вот таких ‘фантомных’ URL’ов:

http://.../foo/quotes/page1.aspx
http://.../foo/quotes/page2.aspx
http://.../foo/quotes/page3.aspx

Этого можно добиться, использовав немного магии – на лету превратив URL вида .../quotes/page1.aspx в URL вида .../rewritepath.aspx?id=1 – использовав метод HttpContext.RewritePath. Хитрость состоит в сборе запросов вида /quotes/page1.aspx, /quotes/page2.aspx из ASP.NET HTTP-канала и превращения их в запрос вида /rewritepath.aspx?id=1, /rewritepath.aspx?id=2 и т.д.. Вот файл Global.asax который это и делает:

<script language=C# runat="server">
   
void Application_BeginRequest (Object sender, EventArgs e)
    {
   
// TODO: превращение пути вида
    // .../quotes/page1.aspx в путь вида
    // .../rewritepath.aspx?id=1
    //
   
HttpContext context = HttpContext.Current;
   
string oldpath = context.Request.Path.ToLower ();
   
string token = "/quotes/page";
   
int i = oldpath.IndexOf (token);
   
int len = token.Length;
    if (
i != -1) {
   
int j = oldpath.IndexOf (".aspx");
    if (
j != -1)
    {
string id = oldpath.Substring (i + len, j - (i + len));
   
string newpath = oldpath.Replace (token + id + ".aspx", "/rewritepath.aspx?id=" + id);
   
context.RewritePath (newpath);
    } } }
   
</script>

Application_BeginRequest вызывается в начале каждого запроса. В этой реализации происходит выделение части URL’a (например, /foo/quotes/page1.aspx), замена этой части на ссылку на реальной странице (например, /foo/rewrite.aspx?id=1) и вызов метода RewritePath для перенацеливания запроса. Попробуйте следующее: перепишите файл RewritePath.aspx в каталог wwwroot на вашем веб-сервере и попробуйте набрать в адресной строке вашего браузера следующее:
http://localhost/quotes/page1.aspx
Сгенерируется ошибка "page not found". Теперь скопируем Global.asax в wwwroot и попробуем ещё раз. На этот раз всё заработает благодаря смене URL’a в событии Application_BeginRequest.
RewritePath используется во многих приложениях. Например, вы можете использовать этот метод для занесения страниц, имеющих параметры в URL’e, в избранное. Этот метод также можно использовать для сокрытия реальных путей в вашем приложении из соображений безопасности. Ну а теперь, когда вы знаете, что метод RewritePath существует, то наверняка сможете найти ему и другое применение.

Автор: hDrummer