InfiniTec - Henning Krauses Blog

Don't adjust your mind - it's reality that is malfunctioning

Using Url rewriting and caching together

The url rewriting...

"Any problem in computer science can be solved with another layer of indirection."
David Wheeler (chief programmer for the EDSAC project in the early 1950s)

URL rewriting is a handy technique to produce much nicer URLs. Instead of http://www.infinitec.de/default.aspx?site=1&subpage=3 a user could use an address like http://www.infinitec.de/exchange/howtos/webdavevents.aspx. When the webserver processes the request, it will rewrite the URL to the webpage that processes the requests and displays the correct content.

In .NET 2.0, this is accomplished by implementing a IHttpModule and registering it in the web.config file.

Here is an example in C#:

    1 using System.Web;

    2 

    3 public class UrlRewriter : IHttpModule

    4 {

    5     #region IHttpModule Members

    6 

    7     public void Dispose() {}

    8 

    9     public void Init(HttpApplication context)

   10     {

   11         context.BeginRequest += context_BeginRequest;

   12     }

   13 

   14     void context_BeginRequest(object sender, EventArgs e)

   15     {

   16         HttpApplication app;

   17 

   18         app = (HttpApplication)sender;

   19 

   20         app.Context.RewritePath("test.aspx");

   21     }

   22 

   23     #endregion

   24 }

The Init method attaches the context_BeginRequest method with the BeginRequest event of the HttpApplication. This implementation redirects each request to the test.aspx in the same virtual directory of the server. In a real world application, this method must extract the necessary information from the original Url and redirect the execution to the correct page for further processing.

To get the sample working, the new module must be registered in the web.config file:

    1 <configuration>

    2   <system.web>

    3     <httpModules>

    4       <add name="UrlRewriter" type="UrlRewriter" />

    5     </httpModules>

    6   </system.web>

    7 </configuration>

You can now open a webbrowser and open any page on the website, regardless if it exists or not. The only restriction is that the extension of the requested page must be registered for the ASP.NET ISAPI filter. Regardless, which page you open, the request is now always processed by the test.aspx file.

When you take a look at the source code of a webpage from your browser, you will notice that the action attribute of the form tag now points back to the test.aspx file, instead of the original URL. A postback would thus reveal the true structure of your website and it might even break the functionality, because the test.aspx file might not know which content to display when called directly.

To solve this problem, the original request path must be restored before the test.aspx file is rendered:

    1 using System.Web.UI;

    2 

    3 public partial class test : Page

    4 {

    5     protected void Page_Load(object sender, EventArgs e)

    6     {

    7         Context.RewritePath("default.aspx");

    8     }

    9 }

For the sake of simplicity, the url is always rewritten to the default.aspx file.

...the caching...

Cashing is a great way to scale your application. Especially when your pages require intensive calculations. Caching is activated on a per-page base by using a page-directive at the top of each page:

    1 <%@ OutputCache Duration="600" VaryByCustom="sitemap" VaryByParam="none" %>

The duration attribute specifies that this page should be cached for 10 minutes (600 seconds). The VaryByParam parameter is set to "none", so any parameters (either POST or GET parameters) are ignored by the caching framework. Finally, the VaryByCustom parameter specifies, that a special method should be called by the the caching framework: The GetVaryByCustomString method, which must be defined in the global.asax file:

    1 <%@ Application Language="C#" %>

    2 

    3 <script runat="server">

    4 

    5     public override string GetVaryByCustomString(HttpContext context, string custom)

    6     {

    7 

    8     }

    9 </script>

...and the problems

Unfortunately, when the caching is used together with URL rewriting, the caching will be unreliable at best...

This is caused by the fact that the caching framework will now cache the output for the wrong url, since it has been rewritten to the test.aspx file. To correct this, the GetVaryByCustomString can be used:

    1 <%@ Application Language="C#" %>

    2 

    3 <script runat="server"> 

    4     public override string GetVaryByCustomString(HttpContext context, string custom)

    5     {

    6         System.Globalization.CultureInfo ci;

    7         string lang;

    8 

    9         if (!custom.Equals("sitemap", StringComparison.CurrentCultureIgnoreCase))

   10             return base.GetVaryByCustomString(context, custom);

   11 

   12         ci = context.Items["CurrentUICulture"] as System.Globalization.CultureInfo;

   13 

   14         lang = ci.DisplayName;

   15 

   16         if (context.Session != null && context.Session["ChosenLanguage"] != null) lang = ((System.Globalization.CultureInfo)context.Session["ChosenLanguage"]).DisplayName;

   17         return (string)HttpContext.Current.Items["OriginalPath"] + ci.DisplayName;

   18     }

   19 </script>

The above implementation returns the original request and the name of the selected language. Thus, a request is served from the ASP.NET cache if the requested path AND the language matches.

This implementation solves the problem that the wrong content ist displayed.


Posted by Henning Krause on Tuesday, December 27, 2005 12:00 AM, last modified on Tuesday, July 26, 2011 9:57 PM
Permalink | Post RSSRSS comment feed