SEO friendly URLs with ASP.NET

Dec 15, 2007

Search engines like human-readable URLs with keywords in it, and hesitate to respect messy URLs with a lot of query-string parameters. So, to make our ASP.NET database-driven website SEO-friendly we have to get rid of our complex URLs.

Example of a "SEO-friendly" URL:
http://www.jitbit.com/mailjet-newsletter-software.aspx

Example of a "SEO-unfriendly" URL:
http://www.jitbit.com/product.aspx?ProductID=18

Solution 1: Fake pages and "Server.Transfer". As you can see the two URLs above point to the same page. Basically it is the same page and it works like this: the page mailjet-newsletter-software.aspx contains no code at all and performs a Server.Transfer (aka server-side redirect) to product.aspx like this:

Server.Transfer("product.aspx?ProductID=18");

That's it. We have one "product.aspx" page which expects a "ProductID" parameter and a lot of "fake pages" with SEO-friendly names like firstproduct.aspx, secondproduct.aspx etc., which simply perform a Server.Transfer to the "product.aspx" with the right ProductID.

Simple, isn't it?

But this solution requires a lot of hard-coding - we will have to create all these fake pages and add a Server.Transfer command. So let's go a little further: we will create one base class for all our "fake pages" and add a record to the "tblProducts" table in the database:

tblProducts
ProductIDProductNameProductPage
1First Productfirstproduct.aspx
2Second Productsecondproduct.aspx
3Third Productthirdproduct.aspx


public class ProductPage : Page
{
private SqlConnection cn;
private SqlCommand cmd;
protected override void OnLoad(EventArgs e)
{
//lets initialize our database connection
//remember to specify the connection string
cn = new SqlConnection(yourConnectionString);
cmd = new SqlCommand();
cmd.Connection = cn;

//determine the page being requested in the browser
string pageFileName = Request.Path.Substring(Request.Path.LastIndexOf("/")+1);

//get the right ProductID from the database
cmd.CommandText = "SELECT ProductID FROM tblProducts WHERE ProductPage=@ProductPage";
cmd.Parameters.AddWithValue("@ProductPage", pageFileName);
cn.Open();
object productID = cmd.ExecuteScalar();
cn.Close();

//if ProductID found
if(productID!=null && productID!=DBNull.Value)
{
//let's transfer the execution
Server.Transfer("product.aspx?ProductID=" + productID.ToString());
}
}
}
Now we have to create our fake pages, inherit them all from the ProductPage class and voi la - that's it! We can also optionally remove all the HTML-code from the aspx-files, leaving the "Page" directive only.

Solution 2: Virtual Pages. This method is pretty similar, except that we don't need to create any pages at all. Instead, we will add an HttpModule, which intercepts HTTP requests, and the user requests a non-existent page, performs a Rewrite operation. First we will create our HttpModule:


namespace URLRewrite
{
public class ProductPageModule : IHttpModule
{
public ProductPageModule()
{
}

public void Dispose()
{
}

public void Init(HttpApplication application)
{
//let's register our event handler
application.PostResolveRequestCache += (new EventHandler(this.Application_OnAfterProcess));
}

private void Application_OnAfterProcess(object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;

//the file being requested is not found
if (!File.Exists(application.Request.PhysicalPath))
{
//replace the "newURL"
//with your own value
string newURL = "product.aspx?ProductID=18";
context.RewritePath(newURL);
}
}
}
}
Now we have to register our HttpModule in the web.config:

<httpModules>
<add type="URLRewrite.ProductPageModule, URLRewrite" name="ProductPageModule" />
<httpModules>

That's it.

8 comments:

Chad said...

This is quite a helpful post, but I was wondering if you could go into a little more detail as to what each line of code is doing so we can all have a better understanding of it.

Alex said...

Thanks for leaving your comment Chad! I have added comments to the code and made it a bit more "readable".

Chad said...

Thanks a lot! It makes more sense now. I am a VB programmer so I don't really know C# as well. The comments help!

Anonymous said...

Will you be implementing this with aspNetForum software? I was looking at purchasing a license, and was considering editing the source to make forum URLS seo friendly.

Alex said...

I am sorry for the delay in responding. Unfortunately the current version does not support SEO-friendly URLs, but we plan to add it in the future.

mayuresh said...

How should the link calling the product page be ? I have something like
Toys

But I get application.Request.PathInfo as empty. Am I missing something ?

Thank you

Anonymous said...

Very useful post... But I am getting an error in the class file ddl I am creating...

Error 1 'URLRewrite.ProductPageModule' does not implement interface member 'System.Web.IHttpModule.Dispose()' C:\Documents and Settings\sacred\Local Settings\Application Data\Temporary Projects\URLRewrite\Class1.cs 8 18 URLRewrite

any ideas?

I started doing this

application.Disposed += (new EventHandler(this.Application_Disposed))

but when I do the cuntion

private void Application_Disposed(Object source, EventArgs e)
{
}

what exactly am I disposing? Confused... in the old days we had a constructor and a destructor... .net I have gotten my head around the way it is suppose to work. As I thought it did the automatic cleanup so no constructing and destructing.

Yet this message indicates otherwise...

Alex said...

simply add this to your module code:

public void Dispose()
{
}

(I will update the article)

Post a Comment