Redirecting from Radio and picking up the links using ASP.NET

One of the biggest hurdles in moving away from Radio and moving blogs in general is, of course, to take all the inbound links with you. To make that work (as you should be able to see if you are hitting any of the permalinks of my old blog), I've written a little HttpModule that will evaluate a set of regular expressions and apply them to the incoming URLs.  

So, first I need to get the links to redirect away from the radio site. In Radio, I've updated the home page template and added the following two things:

1. In the <head> section, I added:
<META http-equiv="REFRESH" content="2; URL=http://staff.newtelligence.net/clemensv/fromradio.ashx?<%radio.weblog.getUrl()+path%>">

This will, if the requested page is */2003/07/18.html indeed redirect to */2003/07/18.txt, but that's acceptable for what's happening next. The redirect will happen after two seconds, because I really want the following JavaScript to fire first.

2. Right after <body>, I added:
<SCRIPT language="JavaScript">
   function redirectToNewSite()
   {
     location.href="http://staff.newtelligence.net/clemensv"+
                      "/fromradio.ashx?"+location.href;
   } 
   redirectToNewSite();
</SCRIPT>

That script will simply redirect using the location.href property. The big difference here is that it will take the bookmark portion with it, which the META tag can't do. So if you are hitting */2003/07/17.html#a219, the target site will be able to pick up the bookmark.

After I did that update, I re-published all weblog entries via Radio and now all of the pages are redirecting automatically to http://staff.newtelligence.net/clemensv/fromradio.ashx?...

On the server, my configuration looks like this:

<configuration>
... <newtelligence.Weblog.UrlMapper>
<!-- the matchExpression values are line-wrapped to fit here!! --> <add matchExpression="(?&lt;basedir&gt;/[\w\.]+)/fromradio\.ashx\?
http\://radio\.weblogs\.com/0108971/(?&lt;year&gt;\d+)/
(?&lt;month&gt;\d+)/(?&lt;day&gt;\d+).*"
mapTo="{basedir}/default.aspx?date={year}-{month}-{day}" /> <add matchExpression="(?&lt;basedir&gt;/[\w\.]+)/fromradio\.ashx\?
http\://radio\.weblogs\.com/0108971/(?&lt;year&gt;\d+)/
(?&lt;month&gt;\d+).*"
mapTo="{basedir}/default.aspx?date={year}-{month}-28" /> <add matchExpression="(?&lt;basedir&gt;/[\w\.]+)/fromradio\.ashx\?
http\://radio\.weblogs\.com/0108971/(?&lt;year&gt;\d+).*"
mapTo="{basedir}/default.aspx?date={year}-12-31" /> <add matchExpression="(?&lt;basedir&gt;/[\w\.]+)/fromradio\.ashx\?
http\://radio\.weblogs\.com/0108971.*"
mapTo="{basedir}/default.aspx" /> </newtelligence.Weblog.UrlMapper> </configuration>

These regular expressions assume that the weblog is in a subweb (which it is) and look for "fromradio.ashx?http://radio.weblogs.com/0108971/" in the URL that's passed in. I don't really have a fromradio.ashx handler registered. Using the *.ashx suffix I am just telling IIS to hand the request over to ASP.NET in order to pass the request down the pipeline. The mapTo expression then picks up what I have been extracting from the incoming URL and maps that to a real URL here.

And here's the HttpModule that does the trick:

namespace newtelligence.Weblog.Web
{
  using System;
  using System.Web;
  using System.Web.UI;
  using System.Configuration;
  using System.Text;
  using System.Collections;
  using System.Collections.Specialized;
  using System.Text.RegularExpressions;

  // reqister this section handler as "newtelligence.Weblog.UrlMapper"
    public class UrlMapperModuleSectionHandler :
    NameValueSectionHandler
  {
    public static string ConfigSectionName
    {
      get
      {
        return "newtelligence.Weblog.UrlMapper";
      }
    }
    public UrlMapperModuleSectionHandler()
    {
    
    }
    protected override string KeyAttributeName
    {
      get { return "matchExpression"; }
    }
    protected override string ValueAttributeName
    {
      get { return "mapTo"; }
    }
  }
  public class UrlMapperModule : IHttpModule
  {
    private EventHandler onBeginRequest;
    
    public UrlMapperModule()
    {
      onBeginRequest = new EventHandler(this.HandleBeginRequest);
    }
    void IHttpModule.Dispose()
    {
    }
    void IHttpModule.Init(HttpApplication context)
    {
      context.BeginRequest += onBeginRequest;
    }
  
    private void HandleBeginRequest( object sender, EventArgs evargs )
    {
      HttpApplication app = sender as HttpApplication;
    
      if ( app != null )
      {
        string requestUrl = app.Context.Request.Url.PathAndQuery;
        NameValueCollection urlMaps = (NameValueCollection)
System.Configuration.ConfigurationSettings.GetConfig(
UrlMapperModuleSectionHandler.ConfigSectionName);         if ( urlMaps != null )         {           for ( int loop=0;loop<urlMaps.Count;loop++)           {             string matchExpression = urlMaps.GetKey(loop);             Regex regExpression = new Regex(matchExpression);             Match matchUrl = regExpression.Match(requestUrl);             if ( matchUrl != null && matchUrl.Success )             {               string mapTo = urlMaps[matchExpression];               Regex regMap = new Regex("\\{(?<expr>\\w+)\\}");               foreach( Match matchExpr in regMap.Matches(mapTo) )               {                 Group urlExpr;                 string expr = matchExpr.Groups["expr"].Value;                 urlExpr = matchUrl.Groups[expr];                 if ( urlExpr != null )                 {                   mapTo = mapTo.Replace("{"+expr+"}",urlExpr.Value);                 }               }               app.Context.RewritePath(mapTo);               break;             }           }         }       }     }   } }

Finally, here's the registration for the config section handler, that should not be forgotten:

<configuration>
  <configSections>
   <section name="newtelligence.Weblog.UrlMapper" 
type="newtelligence.Weblog.Web.UrlMapperModuleSectionHandler, WeblogX" /> </configSections> ... </configuration>

Voila! Works like a charm as you can see.here.

Updated: