In this post, I will show you how I get SharePoint search results in C#.
Before to go deeper, you have to understand the search services (crawls, managed properties, crawled properties …).
We are going to use the dll Microsoft.Office.Server.Search.Query, you might sometimes have some problems with the reference found in the Visual studio references manager (or you might even not found it at all). If so, get the dll in the ISAPI folder.
https://social.msdn.microsoft.com/Forums/sharepoint/en-US/00101fe2-d91e-4d59-a00b-a4d952ef7730/unable-to-find-microsoftofficeserverquery-dll?forum=sharepointdevelopmentlegacy
So let’s create our namespace to get SharePoint results :
using Microsoft.Office.Server.Search.Query; using Microsoft.SharePoint; using System; using System.Collections.Generic; using System.Data; using System.Linq; namespace MyNamespace.SearchResultsService { }
Now we are going to create a method to build the KeywordQuery class. It will create the query for the search.
It’s a bit the same idea with the SPQuery class when you are requesting an SPList to get SPListitems.
private static KeywordQuery KeywordQueryBuilder(string strQuery, string[] selectedProperties, List<Sort> sortedProperties, int rowLimit) { KeywordQuery keywordQuery = new KeywordQuery(spsite); keywordQuery.QueryText = strQuery; // > Select properties // ===> If no selected properties, it will return all values. For better performances, select only needed properties keywordQuery.SelectProperties.AddRange(selectedProperties); // > Manage row limit if (rowLimit > 0) keywordQuery.RowLimit = rowLimit; else keywordQuery.RowLimit = 500; //500 is the maximum than the search can return // > Sorting if(sortedProperties != null){ foreach (Sort sortElement in sortedProperties) { keywordQuery.SortList.Add(sortElement.Property, sortElement.Direction); } } // > Additional parameters keywordQuery.EnableStemming = true; keywordQuery.EnablePhonetic = false; keywordQuery.EnableNicknames = false; keywordQuery.IgnoreAllNoiseQuery = true; keywordQuery.TrimDuplicates = true; keywordQuery.IsCachable = false; return keywordQuery; }
To sort the list, we use a Sort class. A list of this class because we want to be able tu sort with a multi-critera.
public class Sort { public string Property { get; set;} public SortDirection Direction { get; set; } }
Here is the class which will send the request to SharePoint Search.
public static DataRowCollection RequestSearch(string strQuery, int rowLimit, string[] selectedProperties, List<Sort> sortedProperties) { try { // > Build Search Query KeywordQuery keywordQuery = KeywordQueryBuilder(strQuery, selectedProperties, sortedProperties, rowLimit); // > Execute search SearchExecutor searchExecutor = new SearchExecutor(); ResultTableCollection resultTableCollection = searchExecutor.ExecuteQuery(keywordQuery); ResultTable resultTable = resultTableCollection.FirstOrDefault(); // > Select only the results DataRowCollection res = resultTable.Table.Rows; // > Dispose the Search query //keywordQuery.Dispose(); return res; } catch (Exception ex) { throw ex; } }
The next class is not mandatory, but I have created a class to create my Search query. The reason is that it make the query readable in the code. You will see below.
public class PropertySearchQueryBuilder { public PropertySearchQueryBuilder() { properties = new List<string>(); } private List<string> properties {get; set;} public void add(string propertyname, string propertyValue, string condition) { properties.Add(string.Format("{0}{1}\"{2}\"", propertyname, condition, propertyValue)); } public string value { get { string val = ""; foreach (string property in properties) { val += string.Format("{0} ", property); } return string.Format("({0})", val); } } }
All together :
using Microsoft.Office.Server.Search.Query; using Microsoft.SharePoint; using System; using System.Collections.Generic; using System.Data; using System.Linq; namespace MyNamespace.SearchResultsService { private static KeywordQuery KeywordQueryBuilder(string strQuery, string[] selectedProperties, List<Sort> sortedProperties, int rowLimit) { KeywordQuery keywordQuery = new KeywordQuery(SPContext.Current.Site); keywordQuery.QueryText = strQuery; // > Select properties // ===> If no selected properties, it will return all values. For better performances, select only needed properties keywordQuery.SelectProperties.AddRange(selectedProperties); // > Manage row limit if (rowLimit > 0) keywordQuery.RowLimit = rowLimit; else keywordQuery.RowLimit = 500; //500 is the maximum than the search can return // > Sorting if(sortedProperties != null){ foreach (Sort sortElement in sortedProperties) { keywordQuery.SortList.Add(sortElement.Property, sortElement.Direction); } } // > Additional parameters keywordQuery.EnableStemming = true; keywordQuery.EnablePhonetic = false; keywordQuery.EnableNicknames = false; keywordQuery.IgnoreAllNoiseQuery = true; keywordQuery.TrimDuplicates = true; keywordQuery.IsCachable = false; return keywordQuery; } public class Sort { public string Property { get; set;} public SortDirection Direction { get; set; } } public static DataRowCollection RequestSearch(string strQuery, int rowLimit, string[] selectedProperties, List<Sort> sortedProperties) { try { // > Build Search Query KeywordQuery keywordQuery = KeywordQueryBuilder(strQuery, selectedProperties, sortedProperties, rowLimit); // > Execute search SearchExecutor searchExecutor = new SearchExecutor(); ResultTableCollection resultTableCollection = searchExecutor.ExecuteQuery(keywordQuery); ResultTable resultTable = resultTableCollection.FirstOrDefault(); // > Select only the results DataRowCollection res = resultTable.Table.Rows; // > Dispose the Search query //keywordQuery.Dispose(); return res; } catch (Exception ex) { throw ex; } } public class PropertySearchQueryBuilder { public PropertySearchQueryBuilder() { properties = new List<string>(); } private List<string> properties {get; set;} public void add(string propertyname, string propertyValue, string condition) { properties.Add(string.Format("{0}{1}\"{2}\"", propertyname, condition, propertyValue)); } public string value { get { string val = ""; foreach (string property in properties) { val += string.Format("{0} ", property); } return string.Format("({0})", val); } } } }
How to use it :
PropertySearchQueryBuilder psqb = new PropertySearchQueryBuilder(); psqb.add("ContentTypeId", "0X00My_Content_Type_Id" + "*", ":"); psqb.add("ManagedProperties_StartDate", DateTime.UtcNow.ToString("o"), "<="); psqb.add("ManagedProperties_EndDate", DateTime.UtcNow.ToString("o"), ">"); psqb.add("ManagedProperties_Title", "From Search", ":"); string[] SelectedProperties = new string[]{ "ManagedProperties_Title", "ManagedProperties_StartDate", "ManagedProperties_EndDate", "ManagedProperties_Path" }; List<Sort> SortedProperties = new List<Sort>( new Sort[]{ new Sort(){ Property = "ManagedProperties_StartDate", Direction = SortDirection.Descending }, new Sort(){ Property = "ManagedProperties_Title", Direction = SortDirection.Ascending } } ); DataRowCollection results = RequestSearch(psqb.value, 5, SelectedProperties, SortedProperties);