Geeks With Blogs

Scott Van Vliet Once a Developer, Always a Developer

Update 2010-03-23 – Sorry, but the images and downloads were hosted on a server that is no longer available.  I will try to find the sample code bits and images on a backup sometime!

I first came across Search Engine Safe (SES) URLs a year or two ago when Erik Voldengen and Bert Dawson created the CF_sesConverter Custom Tag for ColdFusion applications (http://www.fusium.com/index.cfm?fuseaction=home.buildmaster&bodyFuseaction=ses.intro). 

This tag would accept a modified Query String, which looked like a reference to a static URL, and convert the parameters and add them to the Query String (URL in ColdFusion) scope.  This process made it easier for search engines to spider dynamic Web pages and return them to the user in the search results.

Here’s an example of a standard ASP.NET URL and its SES equivalent.

Standard URL:
http://www.opgirlslearntoride.com/home.aspx?tab=371A6304

SES URL:
http://www.opgirlslearntoride.com/home.aspx/tab/371A6304

I always thought it would be cool if this would be doable in ASP.NET.  At first glance, I remembered that the Request.QueryString collection is read-only, thus you cannot add parameters at runtime.

After looking around the Web a bit, I discovered the RewritePath() method of the HttpContext class.  This method is used to rewrite the path of the request prior to page processing, and is actually used by ASP.NET in a cookieless session state.  Using this method, the URL can be rewritten before being processed by the Page methods and events, thus providing the ability to manipulate the URL Query String at runtime.

Based on this method, an SES URL can be converted into a standard URL using Regular Expressions and some string splitting:

public static string FromSesUrl(string path)

{

Match sesMatch = Regex.Match(

path,

"([\\/].[^\\/]*.aspx)(.*)",
RegexOptions.IgnoreCase);

 

string sesUrlBase = sesMatch.Groups[1].Value;

string sesUrlParams = sesMatch.Groups[2].Value;

 

string urlBase = sesUrlBase;

string urlQueryString = String.Empty;

 

       if (sesUrlParams.Trim().Length > 0)

       {

              sesUrlParams = sesUrlParams.Replace('\\', '/');

              string[] urlParams = sesUrlParams.Split('/');

              for (int idx = 1; idx < urlParams.Length; idx += 2)

              {

                     if (urlParams[idx].Trim().Length > 0)

                     {

                           urlQueryString += (idx == 1) ? "?" : "&";

                           urlQueryString += urlParams[idx];

                           urlQueryString += "=";

                           urlQueryString += (idx + 1 != urlParams.Length) ?

urlParams[idx + 1] : String.Empty;

                     }

              }

       }

 

       return Regex.Replace(

path,

"([\\/].[^\\/]*.aspx)(.*)",

urlBase + urlQueryString,

RegexOptions.IgnoreCase);

}


This method works great and quite fast.  Using this method, you can enable an ASP.NET application to automatically parse SES URLs and Rewrite them to standard URLs. 

However, this is only one piece of the puzzle.  Although you can use SES URLs, it does not make sense to go through your application and replace the existing standard URL references with SES URLs.  So, in order for this method to be effective, there needed to be a way to automatically convert existing standard URL references to SES URLs.  But how can this be done without rewriting source code?

Again, after looking around the Web, I discovered a pretty cool property of the HttpResponse class – the Filter property.  This Stream instance wraps around the HTTP entity body before transmission to the client.  Utilizing this property, I created a custom filter and added some code that would search through the response body and replace standard URL references with SES URLs.

public override void Write(byte[] buffer, int offset, int count)

{

       string sBuffer = Encoding.Default.GetString(buffer, offset, count);

       MatchCollection hrefMatches = Regex.Matches(

sBuffer,

SesRegexPattern.HrefPattern,

RegexOptions.IgnoreCase);

 

       if (hrefMatches.Count > 0)

       {

              foreach (Match match in hrefMatches)

              {

                     string href = match.Groups[match.Groups.Count - 2].Value;

                     if (Regex.IsMatch(href, SesRegexPattern.AspxPattern))

                     {

                           href = href.Replace(href, SesUrlUtil.ToSesUrl(href));

                     }

                     if (!Regex.IsMatch(

href,

SesRegexPattern.HttpProtocolPattern))

                     {

                           if (!Regex.IsMatch(

href,

SesRegexPattern.AbsolutePathPattern))

                           {

                                  href = Regex.Match(

this.Context.Request.Path, SesRegexPattern.CurrentPathPattern)

.Groups[1].Value + href;

                           }

                           sBuffer = sBuffer.Replace(

match.Value,

match.Value.Replace(match.Groups

[match.Groups.Count - 2].Value, href));

                     }

              }

       }

 

       byte[] bufferNew = Encoding.Default.GetBytes(sBuffer);

       this.BaseStream.Write(bufferNew, 0, bufferNew.Length);

}


This method works like a charm, and is also quite fast.

Finally, in order to tie these pieces of functionality together, I created an HttpModule that handled the BeginRequest event of the HttpApplication class.  This event handler first rewrites the SES URL to its standard URL and then adds the custom filter to the Response object of the current context.

It is also good to note that although this filter will rewrite SES URLs, it will allow standard URLs to pass-through without being altered.  Thus, implementing SES for ASP.NET is as simple as two easy steps:

1)      Add the Boardworks.Utilities.SearchEngineSafe.dll to your /bin directory of the ASP.NET application you wish to implement
 

2)      Modify the application’s Web.config file to include the following code:


<httpModules>

<add name="SesHttpModule"

type="Boardworks.Utilities.SearchEngineSafe.SesHttpModule,

Boardworks.Utilities.SearchEngineSafe"/>

</httpModules>


To see this module in action, check out the following site:
http://www.opgirlslearntoride.com

If you have any comments, or better ideas for SES URLs in ASP.NET, please drop me line!  Also, if you would like a copy of this project, please shoot me an email.  If there are enough requests, I will post the Visual Studio .NET Project to this post.

UPDATE:

There's a new version of this module, which includes a small fix to some errant debug code.  NOTE: This link was previously broken, and has been fixed - sorry about that!

http://www.scottvanvliet.com/downloads/ASP_NET_SES_1_0_2.zip

As always, feedback on this would be greatly appreciated!

Posted on Tuesday, May 4, 2004 8:01 AM ASP.NET , C# , Regular Expressions | Back to top


Comments on this post: Search Engine Safe Urls in ASP.NET

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
Without looking too carefully at the code I ask the question - would it be able to handle situations in which you had a QS variable with an empty value - for example...
<br>
<br>?personId=21&amp;orderid=&amp;userId=5
Left by brady gaster on May 04, 2004 12:55 PM

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
and please! post the code!
Left by brady gaster on May 04, 2004 12:57 PM

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
Thanks for your comments. Yes, the filter will handle empty values within a standard URL. It will turn the following URL into its SES counterpart below:
<br>
<br>Standard URL:
<br>/profile.aspx?personId=21&amp;orderid=&amp;userId=5
<br>
<br>SES URL:
<br>/profile.aspx/personId/21/orderid/+/userId/5
<br>
<br>Note that the value of the parameter, orderid, is actually a white space character. This is inserted by the filter, and is required for the parameters to be parsed correctly. The reason for this is that when a URL is passed from the browser to the client, multiple slashes that follow each other are condensed into one slash. For example:
<br>
<br>SES URL:
<br>/profile.aspx/personId/21/orderid//userId/5
<br>
<br>Converted Standard URL:
<br>/profile.aspx/personId=21&amp;orderid=userId&amp;5=
<br>
<br>So, in order to compensate for this condensing, the filter will add a UrlEncoded white space character as depicted above.
<br>
<br>Please let me know if this answers your question.
Left by Scott Van Vliet on May 04, 2004 2:53 PM

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
The code listed in this post contains almost all of the code from the Request.Filter. If you would to see how this all fits together, send me an email and I will get you the source code.
Left by Scott Van Vliet on May 06, 2004 3:55 PM

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
Hi,
<br>
<br>I have been workigng on something similar and I have had issues with images that do not have fully qualified URL (i.e. images/image.gif vs. http://site/images/image.gif). Does this handle them as well?
Left by Robert J Collins (DNN Core) on May 07, 2004 9:59 PM

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
Mike,
<br>
<br>Are you setting the Response.Filter property any where in your code? If so, then this would override the SesUrlFilter. Also, where are you putting the &lt;httpModules&gt; code in the Web.config? It should be under the &lt;configuration&gt;&lt;system.web&gt; node.
<br>
<br>In addition, I have posted a new version of the package. Download it at the URL below:
<br>http://www.brdwrks.com/downloads/ASP_NET_SES_1_0_1.zip
<br>
<br>This new package accomodates for HTML encoded &quot;&amp;&quot; delimiters in URLs created by ASP.NET (i.e. &amp;amp;).
<br>
Left by Scott Van Vliet on May 12, 2004 2:50 PM

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
I am noticing some issues when there are spaces in a URL the override void Write method appears to be chopping off the querystring at the space then reattaching it after the write is completed so the following results:
<br>
<br>This URL
<br>default.aspx?this=that&amp;name=Robert Collins&amp;age=32
<br>
<br>Becomes
<br>defeult.aspx/this/that/name/Robert Collins&amp;age=32
<br>
<br>This in turn when click causes an error…
<br>
<br>Any thoughts?
Left by Robert J Collins (DNN Core) on May 14, 2004 4:34 PM

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
Robert,
<br>
<br>Thanks for your post. I looked into this, and the reason the Query String parameter value is being cut off is due to the HrefPattern Regex. It currently accomodates for any actionable HTML tags (i.e. &lt;A&gt;, &lt;IMG&gt;, &lt;LINK&gt;, etc.) to allow double quote (&quot;), single quote (') and no quote attributes.
<br>
<br>For example, the following tags would all be valid with the filter:
<br>
<br>&lt;a href=&quot;default.aspx?this=that&amp;name=Robert Collins&amp;age=32&quot;&gt;
<br>&lt;a href='default.aspx?this=that&amp;name=Robert Collins&amp;age=32'&gt;
<br>&lt;a href=default.aspx?this=that&amp;name=Robert Collins&amp;age=32&gt;
<br>
<br>However, even without the filter, the unescaped Query String parameter value would give the same results as the SES value in the third example where the HREF attribute is not enclosed in quotes. HOWEVER, if using &lt;asp:Hyperlink&gt; controls, this is a non-issue, as the NavigateUrl must be enclosed in quotes.
<br>
<br>To resolve this, you can update the SesRegexPattern.HrefPattern to this:
<br>
<br>&lt;(a|link|img|script|input|form).[^&gt;]*(href|src|action)=(\&quot;|'|)(.[^\&quot;']*)(\&quot;|'|)[^&gt;]*&gt;
<br>
<br>Notice that the only change here is the exclusion of the \\s identified from the middle group of the HREF attribute pattern. This will now include white space characters in the Query String parameter value.
<br>
<br>Please let me know if this helps, or if you have other questions.
<br>
<br>Thanks!
<br>
<br>Scott
Left by Scott Van Vliet on Jul 14, 2004 5:12 AM

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
<p>Rafiq,</p><p>I&#39;m not sure I follow your question. The module rewrites the requested URL, which should not preclude an automatic PostBack from the DropDownList Control.</p><p>Teo,</p><p>Unfortunately, you will not be able to use a module written in .NET within a Classic ASP application, as these two platforms have different runtime environments. &nbsp;However, you might be able to figure some type of hybrid solution by converting your Classic ASP pages to ASP.NET pages using the aspcompat=&rdquo;true&rdquo; Page directive.</p><p>Thanks for your comments!</p>
Left by skillet on Aug 30, 2006 5:10 AM

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
http://moreaboutmen.com/genre/r-b/g1102/
,http://moreaboutmen.com/genre/r-b/g1102/
Left by Gxzkiye,Gxzkiye on Dec 13, 2007 7:30 PM

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
����� ������� ������� ���������� ������� ����� ������� �� ����� ������ �����.

������

�������




Left by remix8754 on Jan 06, 2009 4:01 PM

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
eFront-Интернет магазин Бытовой и компьютерной техники www.e-front.com.ua
Left by busrider on Jan 11, 2009 12:37 PM

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
������ ����, ������� ������! ����� ���������, ��� �������� ������������ ����� - ������, �� ������� �� ������� ����������� ��������� � ��� ����������� ������ ������ ������������� �������� �� �������� ��������! ��� ������ ������ ����� ������������ ���������� �������! � ��� �� ������� ����� ��� �������������� ������ ������, ��� � ������ ������� (���� ��� ��������). ������ ����� � ��� ��������� ����������� ��������� ���������� �������������� ������ ������������ � �������. �������� � ��� �� ���� � ��������� ������������ �� ���������!





Left by tinoleg on May 18, 2009 3:53 AM

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
������� ������!
��������� ���� ��������� ������� ��� �����
��-���������� �������� � ���������� ������!!!
(��������! ����� ������� ��������� ������ ���������� ����� � �� ������, ������� ������������ ���������� ��� ��������� � �� ���� ���, ������ ��� ������ ��� ����� �������� � ������ ��� ���� ������ ���������. �������� � �������, �� �������������� �������� ������, � ������� ������ �������, ������� ������� ��������� ���� �������� �������! ��� ���� �� ����� �� ��������, ��� ������ �� �� �����������? ����������� ����� - http://www.filehoster.ru/files/db6111

Left by jokfeer on Jul 28, 2009 6:44 AM

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
Site optimization and Site development, could be easier to get good results, many people seek the more you offer your site is not found to be successful only with SEO, - Website Optimization, Digital Marketing.
Left by Televideoweb on Nov 30, 2010 9:55 PM

# re: Search Engine Safe Urls in ASP.NET
Requesting Gravatar...
Nice idea. It is worth learning all this information. - Dr. Thomas Devlin
Left by Robert Nyers on Jan 11, 2017 8:56 AM

Your comment:
 (will show your gravatar)


Copyright © svanvliet | Powered by: GeeksWithBlogs.net