So, I’m continuing my efforts at finding a way to handling Contextual Searching.
To describe the issue again, SharePoint allows you to search ‘This List’ or ‘This Site’. Unfortunately, these searches always show the ‘OSSSearchResults.aspx‘ results page, which is built into SharePoint, can’t be modified, and this means that you can’t use your normal ‘Search Center’ experience, which is usually modified and optimized for your users.
This is a shame, so I’ve been looking at ways of overcoming this problem.
This time, my approach is to use an HTTPModule. An HTTPModule is a piece of code that can process a page request or response before or after SharePoint respectively. Here’s my code
Or in a text:
public class HTTPModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += new EventHandler(RegisterPreInitRequestHandler);
}
void RegisterPreInitRequestHandler(object sender, EventArgs e)
{
Page page = HttpContext.Current.CurrentHandler as Page;
if (page != null)
{
page.PreInit += new EventHandler(page_PreInit);
}
}
void page_PreInit(object sender, EventArgs e)
{
Page page = sender as Page;
if (page != null)
{
if (page.Request.Url.AbsolutePath.Contains("OSSSearchResults.aspx"))
{
page.Response.Redirect("/SearchCenter/Pages/results.aspx" + page.Request.Url.Query, true);
}
}
}
public void Dispose(){}
}
Reading through the code, you can see that when the Page.PreInit event fires, we’re going to check the requested URL. If it contains OSSSearchResults.aspx, we’re going to redirect to a results page in our Search Center.
Fine, this works – but we lose our contextual information. So, what else can we do to keep that?
Previously I’ve blogged about using the Site: search query property to add site context. Well, we can do this too:
Or, in text:
public class HTTPModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += new EventHandler(RegisterPreInitRequestHandler);
}
void RegisterPreInitRequestHandler(object sender, EventArgs e)
{
Page page = HttpContext.Current.CurrentHandler as Page;
if (page != null)
{
page.PreInit += new EventHandler(page_PreInit);
}
}
void page_PreInit(object sender, EventArgs e)
{
Page page = sender as Page;
if (page != null)
{
if (page.Request.Url.AbsolutePath.Contains("OSSSearchResults.aspx"))
{
string queryParams = page.Request.Url.Query;
queryParams = queryParams.Replace(@"&cs=This%20Site", "");
queryParams = queryParams.Replace(@"&cs=This+Site", "");
queryParams = queryParams.Replace(@"&u=", "%20site:");
page.Response.Redirect("/SearchCenter/Pages/results.aspx" + queryParams , true);
}
}
}
public void Dispose() {}
}
All this is doing is removing the &cs parameter, and using the &u parameter for the site: search criteria.
Does it work? Well, let’s run a search:
And here is our results page:
Success! Obviously, for production, you’d need to:
- Make sure it works for all types of query.
- Handle queries on List Context.
- Define what sites this should apply for.
- Choose what page(s) you want to forward searches to!
- Test what its impact on server performance is – I’ve not load tested it!
- Test with Alternate Access Mappings – again, I’ve not tested it!
Thanks!
This post really helped my. A simple solution for my problem
Andy, I wanted to thank you for the good information you’ve been providing on your blog. We ended up implementing some of your approaches, like the HttpModule to avoid the WSS search result page, in our latest product “FC.ImageSearch” and I am happy to give you credit (http://blogs.sharepointdam.com/jen/archive/2010/05/08/fc-imagesearch-released.aspx)
Andy, you probably already took note of it: SP 2010 has an option to set a search result page for the contextual searches in the Site Collection’s Search settings page. This can be used to replace the dreaded OSSSearchResults.aspx, e.g. with the result page of a custom scope.
If the custom scope doesn’t deal with all contextual searches on all libraries or sites it can simply redirect OnPreInit.
As much as I liked your HttpModule I think this is better as it only “interferes” with the contextual searches rather than every HttpRequest.