14/08/2009

Clear | Remove Query Strings From Post Backs (ASP.Net, SharePoint)

As part of an unorthodox request I was asked to make a TabStrip component SEO friendly. My first thought was to completely rewrite the control to make use of GET requests rather than continuing to POST the data back to the server.

Immediately I ran into a problem with this approach as the developers of this site have implemented the majority of these TabStrip controls inside the ASP.Net UpdatePanel (don't get me started with these) which does not recognize GET requests as Async events.

The architect of this site (actually a SharePoint site) failed to recognize that the SharePoint indexing service would not be able to index information on any tab other than the default one (as subsequent requests for tab data are done using Asynchronous Events). When project management asked him to modify the tabs for accessibility he told them it was impossible without a complete redesign.

As a solution to this problem I modified the TabStrip control such that it renders an anchor tag rather than a link button and added some fancy JavaScript to cancel the Anchor tag click event and trigger the appropriate __doPostBack option. I now have a crawl able anchor tag, which works like a link button, and triggers the appropriate update.

Moreover, when the TabStrip is initialized (OnInit) it looks for a specific query string variable indicating the ID of the selected tab. This is when the real problem starts:
  1. Indexing service crawls the anchor and builds a GET string reference to the selected tab id.
  2. Page is loaded into browser.
  3. User selects different tab.
  4. TabStrip is initialized finding the previous (last selected tab) tab id.
  5. TabStrip raises MenuItem Click event ignoring the actual new selected tab id.
The problem then becomes: How do I Clear The Query String From Subsequent Post Back Operations?

My quest turned to the Google.

First I found this approach which actually removes the query string VIA triggering a post back and is therefore too wasteful to be my solution.

I then found the following approach which unfortunately fails to load as it uses the ugly document.all JavaScript method which isn't available until after page load (therefore causes a client side exception - even when registered properly as a StartupScript).

I put together a slightly different JavaScript routine that looks like this:

if(window.onload != null) {
var wol = window.onload;
window.onload = function(e) {
wol(e);
document.forms[0].action = "Index.aspx";
}
} else {
window.onload = function() {
document.forms[0].action = "Index.aspx";
}
}


This JavaScript Method then rolls nicely into an ASP.Net Server Control like so:
///
/// Attempt to remove the tab id from the query string
///

private void AddRemoveTabIdQueryString()
{
const string key = "REMOVETABIDQUERYSTRING";
if (!Page.ClientScript.IsStartupScriptRegistered(GetType(), key))
{
Page.ClientScript.RegisterStartupScript(this.GetType(), key,
string.Format("if(window.onload != null) {{var wol = window.onload;window.onload = function(e) {{wol(e);{0};}}}} else {{window.onload = function() {{document.forms[0].action = \"{0}\";;}}}}", GetRequestPageName()), true);
}

// Get the page Name of the request
private string GetRequestPageName()
{
string rawUrl = Page.Request.RawUrl;
int pos = rawUrl.LastIndexOf("/");
int qpos = rawUrl.LastIndexOf("?");
return qpos > -1 ? rawUrl.Substring(pos + 1, qpos - pos - 1) :
rawUrl.Substring(pos + 1, rawUrl.Length - pos - 1);
}

I hope this is helpful to others.

Over and Out

No comments: