Handling QueryString in Custom Item Resolver processor MVC
On a recent project I was tasked with writing a custom item resolver in Sitecore. The goal was to translate http://domain/blog/tag/tag-name to http://domain/blog?tag=tag name.
Since I had done this a before, I quickly wrote the following code
public override void Process(HttpRequestArgs args)
{
Assert.ArgumentNotNull(args, "args");
if (((Context.Item == null) && (Context.Database != null)) && !string.IsNullOrWhiteSpace(args.Url.ItemPath))
{
Profiler.StartOperation("Custom resolver");
try
{
string qsValue = string.Empty;
string decodedItemName = MainUtil.DecodeName(args.Url.ItemPath);
string blogItemPath = ResolveBlogPath(decodedItemName, out qsValue);
Item blogItem = args.GetItem(blogItemPath);
if (blogItem != null)
{
Context.Item = blogItem;
NameValueCollection queryStringCollection =
StringUtil.ParseNameValueCollection(args.Url.QueryString, '&', '=');
queryStringCollection.Add("tag", qsValue);
args.Url.QueryString = StringUtil.NameValuesToString(queryStringCollection, "&");
}
}
catch (Exception ex)
{
Log.Error("could not resolve url", ex, this);
}
Profiler.EndOperation();
}
}
protected string ResolveBlogPath(string decodedItemName, out string qsValue)
{
qsValue = string.Empty;
try
{
Match match = Regex.Match(StringUtil.EnsurePostfix('/', decodedItemName), @"(^.+/tag/)(.+)/$", RegexOptions.IgnoreCase);
if (match.Success)
{
qsValue = WebUtil.UrlEncode(match.Groups[2].Value);
return match.Groups[1].Value;
}
}
catch (Exception ex)
{
Log.Error("could not resolve url", ex, this);
}
return string.Empty;
}
}
Next, I added my custom processor to the httpRequestBegin pipeline
The code worked fine for all WebForm pages but it did not work for any item that had MVC layout..
After some investigation and a little help from Sitecore support, I found out that Sitecore traditionally has been rewriting URL in the ExecuteRequest processor step.
Here is the magic code:
args.Context.RewritePath(filePath, args.Context.Request.PathInfo, args.Url.QueryString, false);
This processor is never executed on an MVC solution as Sitecore.Mvc.config adds a new processor TransferRoutedRequest immediately after ItemResolver that routes all MVC requests to the appropriate controller, and aborts the pipeline.
The Fix
The fix is simple, all I had to do was
replace the following line:
args.Url.QueryString = StringUtil.NameValuesToString(queryStringCollection, "&");
With this line:
args.Context.RewritePath(blogItemPath, blogItem.Paths.FullPath, StringUtil.NameValuesToString(queryStringCollection, "&"));
Hope this helps you. You can read more about RewritePath on MSDN - http://msdn.microsoft.com/en-us/library/system.web.httpcontext.rewritepath(v=vs.110).aspx