XCentium Blogs
Technical
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
<httpRequestBegin>
<processor patch:after="*[@type='Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel']" type="XCore.SitecoreExtensions.Pipelines.HttpRequestBegin.BlogItemResolver, XCore.SitecoreExtensions" />
</httpRequestBegin>
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.
<processor type="Sitecore.Mvc.Pipelines.HttpRequest.TransferRoutedRequest, Sitecore.Mvc" patch:after="processor[@type='Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel']" />
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