Rewrite Old URLs with Regex into RouteValueDictionary

Have you ever needed to rewrite/redirect old URLs that have very similar pattern as your new, modern URLs, but want to do it with simple, maintainable code?

In the following URL you very specifically can see an ID-value and a potential Category-value.

http://test.com/products/details.aspx?id=123&category=tea-cups

So you probably want to use Regex and point out named groups in above URL.

^(?:.*)\/?products\/details\.aspx\?id=(?<id>[\d]*)(&category=(?<category>[^&]*))?

Then you want to get those named values into a RouteValueDictionary, with above named Keys, like <id> and <category> with the Regex-matched Values in the URL. You can then, for example, send it to a UrlHelper. This is what the following method does:

public static RouteValueDictionary GetRegexRouteValues(string url, string urlPattern)
{
    if (url == null)
    {
        throw new ArgumentNullException("url");
    }
    if (urlPattern == null)
    {
        throw new ArgumentNullException("urlPattern");
    }

    var regex = new Regex(urlPattern);
    var match = regex.Match(url);
    if (!match.Success)
    {
        return null;
    }

    var namedGroupNames = regex.GetGroupNames().Where(x => x != null && !Regex.IsMatch(x, @"^[0-9]+$"));
    var groups = (from groupName in namedGroupNames
                  let groupItem = match.Groups[groupName]
                  where groupItem != null
                  select new KeyValuePair<string, string>(groupName, groupItem.Value)).ToList();

    var routeValues = new RouteValueDictionary();
    groups.ForEach(x => routeValues.Add(x.Key, x.Value));

    return routeValues;
}

Now you can write code that is more easy to read and maintain to redirect specific URLs:

private static void RedirectProductDetails(string requestUrl) {
    string urlRegex = @"^(?:.*)\/?products\/details\.aspx\?id=(?<id>[\d]*)(&category=(?<category>[^&]*))?";
    var routeValues = GetRegexRouteValues(requestUrl, urlRegex);

    routeValues["controller"] = "Products";
    routeValues["action"] = "Details";
    return this.Url.RouteUrl(routeValues);
}
Comments