Setting 301 redirects for a .NET website can often be a daunting task. The problem is that often you are dealing with dynamic pages and static pages. Especially in the case of the dynamic pages, it’s very hard to completely control these redirects from within IIS in a one to one relationship. You will also end up with a site configuration that’s full of junk pages that you don’t need anymore, and before you know it the gruff has built up to an unmanageable extent.
Global Redirect with Global.asax
If you’re familiar with .NET application development, then you should be familiar with the global.asax file. If you enter code into this file it will run on every page on the site. This is perfect for our purposes because we want to check if all incoming requests need to be redirected.
Creating the Dictionary
We don’t want to make a database request every time a page is requested (especially if you’re using a CMS because you’re going to be stressing the database as it is), so we’re going to create a flat text file with our redirect pairs in it. You can create a spreadsheet in excel with 2 columns. The first column will be the root relative path of the old page, and the second column will be the root relative path of the new page.
Save this file out as a “.csv” file (comma separated value), and then change the extension to “.txt”. We’ll name our dictionary file “global-redirect.txt”, and save it in the root directory of our application.
If you open the file in Notepad, it should look something like:
/old/path/1.aspx?id=1234,/new/path/1.aspx
/old/path/2/,/new/path/2.aspx
It’s checking all incoming requests, so it’s going to catch folder paths as well. You can Google “site:yourdomain.com” to see what Google has indexed on your site. This will ensure that you get all of the redirects in place. Also make sure to register your site with webmaster tools for an up-to-date status on your 404s.
Programing Your Redirect Dictionary
Open your “global.asax” page (which will actually open the “global.asax.cs” code file). First we’re going to insert this piece of code at the top of the Global class:
private static Dictionary<string, string> globalRedirect = new Dictionary<string, string>();
This is just a dictionary declaration that we’re going to populate with our text file.
Scroll down to the “Application_Start” request and insert this code:
if (System.IO.File.Exists(Server.MapPath("~/global-redirect.txt")))
{
globalRedirect.Clear();
System.IO.StreamReader input = new System.IO.StreamReader(Server.MapPath("~/global-redirect.txt"));
string inputLine = "";
string[] values = null;
string oldUrl = "";
string newUrl = "";
while ((inputLine = input.ReadLine()) != null)
{
values = inputLine.Split(',');
if (values.Length >= 2)
{
oldUrl = values[0].Trim('"');
newUrl = values[1].Trim('"');
if (!string.IsNullOrEmpty(oldUrl) && !string.IsNullOrEmpty(newUrl) && !globalRedirect.ContainsKey(oldUrl))
{
globalRedirect.Add(oldUrl, newUrl);
}
}
}
input.Close();
}
Basically what this does is check if the file exists and loads it, parses the redirect pairs and adds them to the globalRedirect dictionary, then closes the stream. This happens on application start, so if you add redirect pairs to the text file you’ll have to recycle the application in order to rebuild the dictionary.
Preforming the Redirects on Incoming Requests
Now scroll down to the “Application_BeginRequest” event. Here we’re going to add the code that checks incoming requests.
string url = Request.RawUrl
if (!globalRedirect.ContainsKey(url) && url.IndexOf("?") > 0) url = url.Substring(0, url.IndexOf("?"));
if (globalRedirect.ContainsKey(url))
{
string newUrl = VirtualPathUtility.ToAbsolute("~" + globalRedirect[url]);
try
{
// Create the 301 Redirect
Response.Clear();
Response.Status = "301 Moved Permanently";
Response.AddHeader("Location", newUrl);
Response.End();
return;
}
catch (Exception ex)
{
string err = ex.Message;
}
}
First we check for incoming variables from the RawUrl string. We’ll check the if the raw url is part of the dictionary, and if so we’ll perform the 301 redirect.
We feel that this works really well on large dynamic sites. We recently rebuilt a large directory site, and didn’t want to lose the ranks of the individual directory detail pages. After the initial dictionary rebuild, the performance is fair considering the fact that we didn’t have to redirect users back to generic listing pages.
Credit goes to Muhamet Spahiu for the code, I’m sure that we’ll be using it again. For questions, leave a comment below.