This Queensyrche Eyes of a Stranger post follows Revolution Calling and focuses on how the CSHttpModule processes the data created by the SiteUrlsData Provider. It also serves to tell you about my "URL Handling in Community Server" presentation at Code Camp 6 this past weekend.
I must have done a lousy job marketing Url Handling, because only my buddy Aaron Robinson showed up. (It was a weird Code Camp, as I wasn't the only presenter who faced an empty or near empty room.) I first met Aaron at Code Camp 5 in May, and thanks to him I got to go deeper into Community Server Url handling than had I stayed with the original presentation playbook. That's because Aaron has extensive experience in writing for the HttpApplication object; my talk was all about the url data created by the SiteUrlsData Provider and used by the HttpApplication object. So like creamy peanut butter and milk chocolate, Aaron and I spent the session covering both how the data is created through the SiteUrlsData Provider and how the CSHttpModule processes that data.
Because of the quality time I spent with Aaron we can put the Eyes of a Stranger on the HttpApplication stage of handling site urls in Community Server. Let's process a url while strolling through the CSHttpModule. The Url we're going to handle is
/blogs/tom/archive/2006/10/11/Getting-the-ball-rolling.aspx
The CSHttpModule.cs class of Community Server implements IHttpModule. The BeginRequest Event contains a Create Context with a callback to the CSHttpModule ReWriteUrl method.
CSContext.Create(context, new UrlReWriterDelegate(ReWriteUrl));
The CSHttpModule.ReWriteUrl(HttpContext) method will obtain the working url and write it to the ASP.NET Application context, which is what we're going to walk through.
private bool ReWriteUrl(HttpContext context)
{
string path = context.Request.Path;
// path = "/blogs/tom/archive/2006/10/11/Getting-the-ball-rolling.aspx"
string newPath =
UrlReWriteProvider.Instance().GetRewrittenUrl(path,context.Request.Url.Query);
// newPath = /blogs/post.aspx?App=tom&y=2006&m=10&d=11&PostName=Getting-the-ball-rolling
// (Not shown here, we separate the path from the QueryString)
// With the newPath and QueryString we call the urlProvider (for ASP.NET 2.0
// that would be CSAPSNET20UrlRewriteProvider) and write the actual URL
// to the HttpContext
urlProvider.RewriteUrl(context, newPath, qs);
// with our newPath being "/blogs/post.aspx"
// and our QueryString (qs) as "App=tom&y=2006&m=10&d=11&PostName=Getting-the-ball-rolling"
}
The interesting url handling takes place when creating the newPath value (in bold above.) Here the ReWrittenUrl class cycles through each of its Location object paths looking for a pattern to match the url. When a match is found, the url is converted to the working url with a path and query string.
public virtual string ReWriteUrl(string path, string queryString)
{
...
foreach(ReWrittenUrl url in this)
{
if(url.IsMatch(path))
{
newPath = url.Convert(path,queryString);
CSContext.Current.RewrittenUrlName = url.Name;
break;
}
}
}
So for our url example of
"/blogs/tom/archive/2006/10/11/Getting-the-ball-rolling.aspx"
the matching ReWrittenUrl.Path pattern from our SiteUrlsData provider is
^/blogs/([\w\.-]+)/archive/(\d{4})/(\d{1,2})/(\d{1,2})/([a-zA-Z0-9\-\._]*?)\.aspx
Then, when passed to url.Convert (in bold above), the returned newPath is
/blogs/post.aspx?App=tom&y=2006&m=10&d=11&PostName=Getting-the-ball-rolling
Looking at the ReWrittenUrl.Convert() method, the key statement is
return string.Format("{0}{1}", _regex.Replace(url, _path),qs);
where we know our url is
/blogs/tom/archive/2006/10/11/Getting-the-ball-rolling.aspx
with the SiteUrlData ReWrittenUrl's _path being
/blogs/post.aspx?App=$1&y=$2&m=$3&d=$4&PostName=$5
returns the string
/blogs/post.aspx?App=tom&y=2006&m=10&d=11&PostName=Getting-the-ball-rolling
Now back to our CSHttpModule.ReWriteUrl(HttpContext) method where we will separate the query string from the url path and pass those to HttpContext.RewritePath().
if(newPath != null)
{
string qs = null;
int index = newPath.IndexOf('?');
if (index >= 0)
{
qs = (index < (newPath.Length - 1)) ? newPath.Substring(index + 1) : string.Empty;
newPath = newPath.Substring(0, index);
}
urlProvider.RewriteUrl(context, newPath, qs);
}
At this stage, like Yul Brynner says in Ten Commandments, "So shall it be written, so shall it be requested by the ASP.NET Application Object."
Today's episode Operation Mindcrime theme song: Eyes of a Stranger.
[Queensryche]