Get SharePoint search results in C#

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);