Problem

Here I have an URL with a query string:

https://hiddenfoundry.com/page?id=123

I don't like this query string, I want a friendly segment instead:

https://hiddenfoundry.com/page/123

How do I go about making this change in Optimizely?

Solution

Optimizely provides an interface called IPartialRouter which allows you to do just this. Here's what the complete code looks like:


public class YourPagePartialRouter : IPartialRouter<YourPage, YourPage>
{
    public PartialRouteData GetPartialVirtualPath(YourPage content, 
        string language, 
        RouteValueDictionary routeValues, 
        RequestContext requestContext)
    {
        return null;
    }

    public object RoutePartial(YourPage content, SegmentContext segmentContext)
    {
        var segmentPair = segmentContext.GetNextValue(segmentContext.RemainingPath);
        segmentContext.RouteData.Values["id"] = segmentPair.Next;
        segmentContext.RemainingPath = segmentPair.Remaining;
        return content;
    }
}

Let's break this down.

A. public class YourPagePartialRouter : IPartialRouter<YourPage, YourPage>

Implement a class inheriting from IPartialRouter. You'll notice we need to specify two generic parameters: IPartialRouter<TContent, TRoutedData>

  • The first one (TContent) tells Optimizely which page type we want the partial router to kick in and do its work.
  • The second one (TRoutedData) allows us to tell Optimizely what page type we intend to route too.

In our example, both TContent and TRoutedData are the same.

By inheriting the interface you must implement two methods. GetPartialVirtualPath and RoutePartial.

 

B. GetPartialVirtualPath() - We don't need this.

GetPartialVirtualPath() from the full example you can see we return a null. We don't care about generating a url when requested since we are treating the last segment as a query parameter.

 

C. RoutePartial() - Breaking down the magic

Grab the next segment pair which contains the next segment and also the remaining path.

var segmentPair = segmentContext.GetNextValue(segmentContext.RemainingPath);

Assign the next segment to our routed parameter. In our example, segmentPair.Next would equal to "123"

segmentContext.RouteData.Values["id"] = segmentPair.Next;

Assign what's left the the remaining path for the next pass when it iterates over.

Note we don't not pass an empty string here. This would effectively be instructing the partial router to ignore the remaining path, meaning any combination of paths after what we've already processed would resolve to this page. Not good for seo!

segmentContext.RemainingPath = segmentPair.Remaining;
return content;