My previous post explained technique of altering the search results presentation using XSLT. Though I prefer using XSLT for presentation related changes, server side changes to search logic is not possible using XSLT. This post describes technique on extending the out of the box CoreResultsWebPart for adding server side logic to search query execution.

The example in this post will provide a web part property, named Extended Keyword Query, which will allow designers to add additional query filters to keyword query issued by end user. A scenario where this could be useful is when you need to have a custom search results page that only displays results that are tagged as Documents in SharePoint. This could also be achieved by end user using Advanced Search with Results Type as ‘Document’ (see figure 1). In our example, end user simply enters keyword in search box and the results will only include content tagged as Document.

Figure 1

We will start with creating a web part class that inherits from CoreResulsWebPart. Start a new Project in Visual Studio.NET. If you have VseWSS installed, select SharePoint –> Web Part template. Add Microsoft.SharePoint.dll and Microsoft.Office.Server.Search.dll as Reference.

Declare a private field named _extendedQuery that will hold value for the additional query term.

   1: [Guid("d6d212a1-dbca-4150-b023-e64c480bc8b6")]
   2:     public class AdvSearchResultsWebPart : Microsoft.Office.Server.Search.WebControls.CoreResultsWebPart
   3:     {
   4:         private string _extendeQuery = String.Empty;
   5:  
   6:         public AdvSearchResultsWebPart()
   7:             : base()
   8:         {
   9:             
  10:         }

Add a new web part property named, Extended Keyword Query, that lets designer specify additional query term.

   1: [Personalizable(PersonalizationScope.Shared)]
   2:     [WebBrowsable(true)]
   3:     [System.ComponentModel.Category("Advanced")]
   4:     [WebDisplayName("Extended Keyword Query")]
   5:     public string ExtendedQuery
   6:     {
   7:         get { return _extendeQuery; }
   8:         set { _extendeQuery = value; }
   9:     }

Next we override OnLoad method where we merge the keyword query entered by end user with additional query term specified in the Extended Keyword Query web part property.

   1: protected override void OnLoad(EventArgs e)
   2:         {
   3:             base.OnLoad(e);
   4:             if (base.xmlResponseDoc == null) // add additional term only if query hasn't been executed
   5:                 SetAdditionalQueryTerm();
   6:         }
   7:  
   8:         private void SetAdditionalQueryTerm()
   9:         {
  10:             if (String.IsNullOrEmpty(_extendeQuery))
  11:                 return;
  12:  
  13:             object queryObject = HttpContext.Current.Items["OSSSRHDC_0"];
  14:             Type valType = queryObject.GetType();
  15:             PropertyInfo fullTextQueryProp = valType.GetProperty("FullTextQuery", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
  16:  
  17:             string query = (String)fullTextQueryProp.GetValue(queryObject, null);
  18:  
  19:             if (!_extendeQuery.StartsWith(" "))
  20:                 _extendeQuery = " " + _extendeQuery;
  21:  
  22:             if (String.IsNullOrEmpty(query)) // This is Keyword search
  23:             {
  24:                 PropertyInfo keywordQueryProp = valType.GetProperty("KeywordQuery", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
  25:                 query = (String)keywordQueryProp.GetValue(queryObject, null);
  26:  
  27:                 string additionalTerm = String.Empty;
  28:                 
  29:                 if (!query.Contains(_extendeQuery)) // Set additional term only if it is not set already
  30:                 {
  31:                     keywordQueryProp.SetValue(queryObject, query + _extendeQuery, null);
  32:                 }
  33:             }
  34:         }
  35:  

The OnLoad method invokes SetAdditionalQueryTerm private method that does the actual work of merging query terms. Lets examine the SetAdditionalQueryTerm method closely.

   1: object queryObject = HttpContext.Current.Items["OSSSRHDC_0"];
   2: Type valType = queryObject.GetType();
   3: PropertyInfo fullTextQueryProp = valType.GetProperty("FullTextQuery", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
   4: string query = (String)fullTextQueryProp.GetValue(queryObject, null);

CoreResultsWebPart stores an object named OSSSRHDC_0 in HttpConext. This object is of type Microsoft.Office.Server.Search.WebControls.SearchResultHiddenObject and contains various information such as Keyword Query, FullTextQuery etc. as its properties. Since SearchResultsHiddenObject is actually hidden, we cannot cast it to its orginal type; therefore, we cast it to System.Object,

Note: As this is a hidden object as in not documented in SDK, we should keep in mind that it may not work in next version of SharePoint.

Next three lines (2,3 and 4) uses Reflection to retrieve value from FullTextQuery property from the hidden object. This property contains SQL for search query in case the end user uses Advanced Search.

Following lines of code merges query variable – that contains query issued by end user – and _extendedQuery variable – that contains the additional query term from the web part property. Finally it sets the merged query term to the KeywordQuery property. CoreResultsWebPart uses the query term from KeywordQuery property to query the SharePoint index using keyword syntax

   1: if (!_extendeQuery.StartsWith(" "))
   2:     _extendeQuery = " " + _extendeQuery;
   3:  
   4: if (String.IsNullOrEmpty(query)) // This is Keyword search
   5: {
   6:     PropertyInfo keywordQueryProp = valType.GetProperty("KeywordQuery", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
   7:     query = (String)keywordQueryProp.GetValue(queryObject, null);
   8:  
   9:     string additionalTerm = String.Empty;
  10:     
  11:     if (!query.Contains(_extendeQuery)) // Set additional term only if it is not set already
  12:     {
  13:         keywordQueryProp.SetValue(queryObject, query + _extendeQuery, null);
  14:     }
  15: }

 

 

 

 

 

Now you are all set. Final steps, which I won’t go in details, is to package the code as Feature and deploy it to SharePoint Farm. To put this web part in action, browse to SharePoint search results page, Edit the page, delete the CoreResultsWebPart and add the web part you just deployed.

When you modify this web part, you will see the new Extended Keyword Query property under Miscellaneous category. Enter IsDocument:1 (figure 2)in this property. This will further filter your search results to display content that are tagged as ‘Document’ in SharePoint index.

Figure 2

image

Any keyword search that directs search results to page that contains your modified web part, will always filter content that are tagged as Document.

Note: IsDoucment:1 is just an example. You can add it to any managed property filter. For example Site:http://yoursharepointsite/sites/customer. This web part will support all keyword query syntax.

Entire code for this web part can be accessed from:

http://cid-ed3f2f28de595784.skydrive.live.com/self.aspx/Public/Sharepoint%20Search/AdvSearchResultsWebPart.cs

-Arbindo