Custom Document Aliases in Kentico CMS
(Note: this post assumes that you read the primer post on URL Rewriting & Aliasing in Kentico CMS)
In my last post I described what it takes to use the URL Rewriting and Document Aliasing capabilities of Kentico. I also promised a twist to those who made it through the entire blog post, and here it is. So without further ado, I now present my solution for creating a Custom Document Alias in Kentico that is QueryString aware.
Let’s get started. Now that you understand more about URL Rewriting say you had a URL like this:
http://mcbeev.com/products/item.aspx?type=Chips&name=Baked Lays
Pretend for a minute that your store also sold candy bars, and we decided to reuse the same old page to display both types of products. We would still have a URL like:
http://mcbeev.com/products/item.aspx?type=Candy Bars&name=Snickers
Our example translated into a standard Kentico setup:
And here ladies and gentlemen we hit our first snag with the Kentico CMS out of the box and aliasing. You can URL Rewrite and even Document Alias any node in the content tree. However, the one small gotcha is that you can not create an Alias that looks at QueryString values, or anything after the question mark.
The default Kentico engine will just replace any special character with a dash in the in the URL Path or URL extension field of the Document Alias, therefore wiping out the important part of the QueryString that our example URL above is relying on.
I have actually run into this in my real world projects where I am upgrading a pre existing site that has lots of old links from it’s website as well as other websites that match the URL format in our above example.
Bummer.
To fix this we have to get a little creative and write some code. This is a two part solution. First, we need to make a generic redirector page with a Document Alias of the first part of the URL above.
I created a new page called RedirectItems at the root of my Kentico site and then added a Document Alias like so:
The purpose of this page will be catch all the incoming requests regardless of QueryString value, and hand it off to the right place after running a bit of code on that page, or Web part.
The next step we need to do is create a new custom Web part. The purpose of this new Web part will be to to grab the information out of the the request that we need. To do so I used these instructions from Kentico on how to create a new custom Web part.
The key here is that we create the new Web part called Redirector (or whatever you like) and then give it one Property called RedirectToPaths. This is where you will set your URL templates for how we can handle the QueryString redirects.
At this point you are safe to click save on the Create Web part Screen. Next we need to add in some code to our Web Part.
Once the new Web Part is added in the CMSSiteManager and the file is in ~/CMSWebParts/Your Category Name/ you can open up the source code of Redirector.ascx.cs with your favorite Text Editor or Visual Studio. And add the following OnPreRender method.
protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); if (this.StopProcessing) { // Do nothing } else { //Collect the URL information from the current Request string currURL = HttpContext.Current.Request.RawUrl; string queryString = string.Empty; string newURL = string.Empty; //Check to make sure some query string variables exist int iqs = currURL.IndexOf('?'); //QueryString variables exist, put them in a string. if (iqs >= 0) { queryString = (iqs < currURL.Length - 1) ? currURL.Substring(iqs + 1) : string.Empty; } if(queryString.Length > 0) { //Parse the querystring NameValueCollection qsKeys = HttpUtility.ParseQueryString(queryString); //Pull in the Path Expressions from the Web Part property called RedirectToPaths string redirectToPaths = (string) this.GetValue("RedirectToPaths"); //If the property is empty do nothing if(redirectToPaths.Length > 0) { //Split out the property value by a comma in case there are multiple foreach(string p in redirectToPaths.Split(',')) { string path = p; bool allKeysInPath = true; //Iterate through the keys and replace the key with the value foreach (string key in qsKeys.AllKeys) { if(path.Contains("{"+ key + "}")) { path = path.Replace("{"+ key + "}", qsKeys[key]); } else { allKeysInPath = false; } } //Handle whitespace path = path.Replace(" ", "-"); //Make sure we got a redirectToPath that handles all the keys if(allKeysInPath) { newURL = path; break; } } //Check if we generated a new URL if(newURL.Length > 0) { //Redirect to our new path Response.Redirect(newURL); } } } } }
That’s all the code we need to touch, so close and save the file. Now let’s add our new Redirector Web Part to our site. Open up the CMSDesk again and go to where you created the page called RedirectItems from above. Click on the Design tab of the page and add in new Redirector Web Part that we just created. Then click configure. You should be at a modal window that looks like this:
Notice our RedirectToPath property shows up and I have typed in two URL templates. Go ahead and copy the second string /Products/{type}/{name} into your Web part. Then click OK. I think you can probably guess how that maps to our original problematic URL of:
http://mcbeev.com/products/item.aspx?type=chips&name=Baked Lays
Basically the code will replace anything inside the curly brackets that matches the name of the parameter with the value of the parameter. So for the preceding example, we will end up being redirected to the correct location of:
http://mcbeev.com/Products/Chips/Baked-Lays
So there you have it, this custom Web part will now give us a small enhancement to the built in ability of Document Aliasing for Kentico CMS. The code for the Web part can be found at the link below.
I hope this idea helps you maintain working links when upgrading a pre existing site the way it did for me. As always please feel free to leave feedback for me in the comments.