iFinity Blogs 

Redirecting bad Urls in DotNetNuke

by Bruce Chapman on Monday, October 29, 2012 1:31 PM

Recently I delivered a talk at the Orlando DotNetNuke User Group (ODUG) – the topic was ‘Url Best Practice for DotNetNuke’.   I enjoyed giving a talk to an enthusiastic audience and fielded some great questions, anecdotes and was hopefully able to impart some valuable knowledge to the attendees.  I have learned a lot of lessons in the years that I have been working in the Url space and some of those lessons are learnt the hard way.

[The entire presentation was recorded and is available at ODUG Meeting October 2012)

One thing I raised in the talk was the ability to use the siteurls.config file in DotNetNuke to handle redirects.  While this is an old feature of DNN (it has been around for many versions) there were quite a few people in the room who weren’t aware of it.

Today I was trying to sort out a problem with this site, and while checking the event log, I noticed a pile of exceptions from a bot that was hitting the site with malformed Urls.  One of these exceptions is shown below:

image

Essentially a bot had come up with a Url which looked like this:

/Products/Support_Forums/forumid/8/postid/1432/scope/__doPostBack('dnn$ctr993$UrlOptions$lblRedirectResultsLabel$cmdHelp','')

It’s probably from someone posting some Html in a forum, which can end up with unfollowable links.  But it’s clogging up the event viewer so it needs to be dealt with.

The easiest thing for me to do is to plug this into Url Master to redirect back to the Support Forums page, by entering ‘Products/Support_Forums/forumid/8/postid/1432/scope/__doPostBack('dnn$ctr993$UrlOptions$lblRedirectResultsLabel$cmdHelp','')’ as a 301 redirect for the Support Forums page.

A quick check on the test function, and I can see it’s working OK:

image

However, this approach isn’t available unless you have the module, and doesn’t scale well if the bot is hitting many different variations of the underlying Url.

And sure, enough, if I poked through a few more pages of Urls, I find similar bad Urls being requested:

/Products/Support_Forums/forumid/8/postid/2415/scope/__doPostBack('dnn$ctr745$UrlOptions$lblDoNotRedirectRegex$cmdHelp','')

/Products/Support_Forums/forumid/8/threadid/6443/scope/__doPostBack('dnn$ctr1103$PageList$lblPortalAliasUsage$cmdHelp','')

What I need was a more generic capture-and-redirect strategy to find these bad Urls and redirect them to a valid page, where they wouldn’t throw an error.

Using the siteurls.config file to redirect Urls

What I decided to do was use this as a teaching moment to show how to redirect a bad Url using the in-built DotNetNuke tools.

For this, we need to use some simple regex (cue groans at the back of the room).  This goes into the ‘match’ part for the rules (or the ‘lookFor’ if you’re working with the file directly, rather than using the UI).

It’s simple regex because we just need to match the same basic pattern, but allow for variations in the postId/threadId and the different ‘doPostBack’ values.

This is the regex I came up with:

.*/Products/Support_Forums/forumid/(\d+)/(postid|threadid)/(\d+)/scope/__doPostBack[^/]+

This will match either of the two Urls listed above which are throwing the error. 

Breaking it down:

.*/ matches the first part of the Url, essentially the domain name

Products/Support_Forums is a direct match – this just matches if this is found in the Url

/forumid/(\d+) is a combination of directly matching the text, but also matching any integer value for the forumId (forumId/ – text match, \d+ – any combination of digits [\d])

/(postId|threadid)/(\d+) matches either postid or threadId (the | is an ‘or’ operator) and also any matching integer value.

/scope/__doPostBack[^/]+ matches when the /scope/ value has been provided with any __doPostBack…. value.  The [^/]+ means match any combination of characters, as long as they are NOT / (^ is the not operator).  So it just means match the rest of the Url if it starts with __doPostBack.

The second part of doing a redirect is telling DotNetNuke where to send it.  This is done by writing another (gasp) regex expression.

Here’s the regex I wrote to go with the ‘match’ part, which is the ‘Replace With’ value:

http://www.ifinity.com.au/Products/Support_Forums/forumId/$1/$3/$4/scope/posts

The key here is that the above value is an absolute Url – it includes both the domain name and the http://.   This is the way to differentiate from a rewrite rule and a redirect rule in the siteurls.config file.   This is the point I discussed at ODUG, which many people did not know.

In comparison to the match regex, this looks rather tame.  It’s just the absolute Url for the redirect, but with placeholders for matched sections from the first regex.  Wherever the ‘match’ regex has an expression in brackets, it’s called a ‘capturing group’.   And we can refer to the results of that group just by number, reading left to right.  That’s what the $1, $2, $3 etc means – take the matched values from the ‘match’ expression and put them into these spots.  So it will copy across the forumId, postId/threadId value, and the results of the postId/threadId parameter, and use that for the redirected Url.

That flexibility saves me from having to enter a different Url for each match that is possible.

This is entered directly into the Host Settings->Friendly Url Settings section, and saved.

image

(click image to enlarge – yes, the length of the rule breaks the layout somewhat)

You can also enter the rules directly into the siteurls.config file if you want (but be sure to use an xml encoder to make sure they are xml-legal)

image

Now that’s done, we can test the Url and see if it works OK.   I always check with Fiddler, but you can just use your browser to see. 

image

You can see that the Urls are now being redirected to a good, clean Url and won’t be bothering my event viewer anymore.

Note for Url Master users

Url Master takes precedence over the siteurls.config rules, so if you want a siteurls.config rule to run, you will need to add a bit more regex to the Url Master settings.

For this one, I just added |/scope/__doPostBack[^/]+ to the end of the ‘useSiteUrlsRegex’ pattern, which specifically identifies these Urls ending with /scope/__doPostback and then sends them to the siteurls.config file for processing.

Blogs Parent Separator Crafty Code
Author
Bruce Chapman

The craft of writing code. The outcomes from being crafty with code. Crafty Code is tales from the coding bench.

Bruce Chapman
Hi, I'm Bruce Chapman, and this is my blog. You'll find lots of information here - my thoughts about business and the internet, technical information, things I'm working on and the odd strange post or two.
Connect with Bruce Chapman on Google+

Share this page
Get more!
Subscribe to the Mailing List
Email Address:
First Name:
Last Name:
You will be sent a confirmation upon subscription

Follow me on Twitter
Stack Exchange
profile for Bruce Chapman at Stack Overflow, Q&A for professional and enthusiast programmers
Klout Profile