Rewriting website Urls in C#.NET

Posted on: August 18th, 2011 by
Comments Requested

In another article I’ve talked about the importance of rewriting your urls. ASP.NET gives you the huge advantage of being able to dynamically create your pages from the server-side. And so, you won’t need to have separate physical pages for each of your content pieces when they are very similar in nature. For example, if you’re displaying multiple articles on your site with the same design just different content, you just need to have one .aspx page for this process and dynamically pull the title, description, time, etc. into the page from your database/storage. Because of this functionality, you will need to somehow determine which content to grab when your users hit your .aspx page. You can do this many ways, some involving session variables. But, the most popular way to do this is to pass a variable in the url, or QueryString variable. And so, your urls will end up looking something like this: ‘mydomain.com/book.aspx?id=23′ and ‘mydomain.com/book.aspx?id=34′.


This format is fine for your .aspx page and it’s great for determining which content to grab, however, it’s horrible for SEO and for human readability. Search engines pay special attention to the keywords in your url. And, more specifically, they give more credit to the keywords closer to the begining of your url. So, it is really important to have urls that are humanly readable. For example ‘mydomain.com/my-book-name’ as opposed to ‘mydomain.com/book.aspx?id=23′. For this to happen, we need to rewrite this type of url in our web application to something more readable.

In this article, I explain how to rewrite urls in your C#.NET/ASP.NET application. I provide here two simple examples of url rewrites first and then two more complex examples.

Skip down to the completed solution.


<configuration>
<system.web>
<httpModules>
<add name=”Localization” type=”RewriteHttpModule” />
</httpModules>
</system.web>
</configuration>



public class RewriteHttpModule : IHttpModule
{
public void Init(HttpApplication context)
{

context.BeginRequest +=
new System.EventHandler(this.context_BeginRequest);
}


public void Dispose()
{
}
private void context_BeginRequest(object sender, EventArgs e)
{

HttpRequest request = ((HttpApplication)(sender)).Request;
HttpContext context = ((HttpApplication)(sender)).Context;
HttpResponse response = ((HttpApplication)(sender)).Response;

string applicationPath = request.ApplicationPath;

if ((applicationPath == “/”))
{
applicationPath = String.Empty;
}

string requestPath =
request.Url.AbsolutePath.Substring(applicationPath.Length);

//Redirect conditions

}
}

[blue]

To begin with, we have to specify our rewrite module in the web.config file’s httpModules section. Include here the name of your class that will perform the url rewrite; ‘RewriteHttpModule’ in our case.

[yellow]

Next we create our’RewriteHttpModule’ class and place it in the App_Code directory in our project. Make sure that your class inherits from IHttpModule and matches up with the name you specified in your web.config file. [The App_Code directory is a folder that ASP.NET pays special attention to. If you don't already have the App_Code directory included in your project, right click your project in Solution Explorer and click on Add -> New Folder. Rename the new directory to 'App_Code'. After you have created the App_Code directory, right click on it and Add -> New Item. Add a .cs file and name it 'rewrite'.] Your directory should look like this:

Rewrite Tree View
[yellow]

We need three specific functions to implement our rewrite: public void Init(HttpApplication context), public void Dispose() and private void context_BeginRequest(object sender, EventArgs e). In this case, we will not be using the Dispose() function, however, if you do not include it, the compliler will complain. In the Init function we have to make sure to assign a handler which will be called upon every url request that our users make to our domain. In our case, our handler is the context_BeginRequest function. And so, when a user request the url ‘mydomain.com/name-of-book’, context_BeginRequest will inspect it and check for any cases that have been specified for the string ‘name-of-book’. If it finds a case for that specific string it can rewrite the url to something that would be useful to the application, ex: ‘Article.aspx?ID=34′, redirect the application there and leave the pretty url for the user to see. If the handler does not find a case for the string ‘name-of-book’, it leaves the url alone and directs the application to that url. Of course, if the application does not understand the string ‘name-of-book’ it will give you an error, so make sure you include all the case applicable to your application.

[red]

Here you can include the redirects specific to your application. What I have is two simple static examples that make the ‘.aspx’ part of the page url unnecessary, which is also a neuisance for your users and does not look too pretty. Every time the requestPath part of the url is ‘/home’ context_BeginRequest rewrites it internally to ‘home.aspx’. The second case is similar for’/about’.


The last two, more complex examples involve grabbing an index from the url to determine the specific content to grab out of the database. In the url in question, I include the database index of the specific content close to the end of the url. The index, in my example, is needed because titles for my articles are not unique, and so, I cannot grab the content based on the title. I place the index near the end of the url as it is better for SEO. Remember, search engines pay speciall attention to keywords in the url especially those closer to the beginning of the string.

And so, following our more complex example, the application will see a url come though similar to ‘http://TheCodeBug.com/Url-Redirecting-Article_23_Blog’. Because the index that I need to grab is at the end of the url, i reverse the requestPath, check the type of page we are dealing with and, redirect it to the appropriate .aspx page using a QueryString variable attached to the end of the url.

The first example checks whether we are delaing with a ‘Blog’ page. First it checks whether the end of the url is the reversed ‘Blog’ string, ‘golB_’. Then it grabs the index of the content we need to display on the Blog.aspx page. When we are done with constructing the url we end up with something like ‘http://TheCodeBug.com/Blog.aspx?ID=34′, which our application understands, and the user continues to see the pretty url ‘http://TheCodeBug.com/Url-Redirecting-Article_23_Blog’. We do the same thing for the ‘Trip.aspx’ page and end up with something like ‘http://TheCodeBug.com/Trip.aspx?ID=24′.


if (requestPath.ToLower() == “/home”)
{
context.RewritePath(applicationPath + “/home.aspx”);
}
else if (requestPath.ToLower() == “/about”)
{
context.RewritePath(applicationPath + “/about.aspx”);
}
else
{
//Make sure when you check the substring of requestPath, it will have
//a sufficient index of elements
if (requestPath.Length > 5)
{
if (requestPath.Substring(0, 5) == “golB_”)
{
int start = 5;

string theI = requestPath.Substring(start, 1);
while (int.TryParse(theI, out theIntOut))
{
theInt = theIntOut.ToString() + theInt;
theI = requestPath.Substring(++start, 1);
}

context.RewritePath(applicationPath + “/Blog/Article.aspx?ID=” + theInt);
}
else if (requestPath.Substring(0, 5) == “pirT_”)
{
int start = 5;

string theI = requestPath.Substring(start, 1);
while (int.TryParse(theI, out theIntOut))
{
theInt = theIntOut.ToString() + theInt;
theI = requestPath.Substring(++start, 1);
}

context.RewritePath(applicationPath + “/Trip.aspx?ID=” + theInt);
}
}

}


You can keep on adding many more cases for your redirects and for all the necessary pages in your .NET application.

And here is the completed solution.


<configuration>
<system.web>
<httpModules>
<add name=”Localization” type=”RewriteHttpModule” />
</httpModules>
</system.web>
</configuration>



public class RewriteHttpModule : IHttpModule
{
public void Init(HttpApplication context)
{

context.BeginRequest +=
new System.EventHandler(this.context_BeginRequest);
}


public void Dispose()
{
}
private void context_BeginRequest(object sender, EventArgs e)
{

HttpRequest request = ((HttpApplication)(sender)).Request;
HttpContext context = ((HttpApplication)(sender)).Context;
HttpResponse response = ((HttpApplication)(sender)).Response;

string applicationPath = request.ApplicationPath;

if ((applicationPath == “/”))
{
applicationPath = String.Empty;
}

string requestPath =
request.Url.AbsolutePath.Substring(applicationPath.Length);

if (requestPath.ToLower() == “/home”)
{
context.RewritePath(applicationPath + “/home.aspx”);
}
else if (requestPath.ToLower() == “/about”)
{
context.RewritePath(applicationPath + “/about.aspx”);
}
else
{
//Make sure when you check the substring of requestPath, it will have
//a sufficient index of elements
if (requestPath.Length > 5)
{
if (requestPath.Substring(0, 5) == “golB_”)
{
int start = 5;

string theI = requestPath.Substring(start, 1);
while (int.TryParse(theI, out theIntOut))
{
theInt = theIntOut.ToString() + theInt;
theI = requestPath.Substring(++start, 1);
}

context.RewritePath(applicationPath + “/Blog/Article.aspx?ID=” + theInt);
}
else if (requestPath.Substring(0, 5) == “pirT_”)
{
int start = 5;

string theI = requestPath.Substring(start, 1);
while (int.TryParse(theI, out theIntOut))
{
theInt = theIntOut.ToString() + theInt;
theI = requestPath.Substring(++start, 1);
}

context.RewritePath(applicationPath + “/Trip.aspx?ID=” + theInt);
}
}

}


}
}

The last thing to mention is that, if you are rewriting your urls, you will now have at least two ways of getting to your page’s content. Search engines view this as duplicate content since it views the different urls as two separate pages. To remedy this situation, make sure you include the ‘canonical’ tag in your header for each page whose url you are rewriting. Here’s an article on how to do so

For more reading on rewritting urls visit:

  1. Wikipedia – Rewrite engine
  2. MSDN – URL Rewriting in ASP.NET

Tags: ,

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>