In the previous installment of this article, Utilizing The Power Of SharePoint Search – Part 1 (Centralizing Search Results From Mulitple Sources), we configured the SharePoint Search Application to index some external resources, and make that content centrally searchable from within SharePoint.
In this section of the article I’m going explain how SharePoint can be used as the backend search provider for a non-SharePoint website. Microsoft provided us with a few great routes to retrieve search results from SharePoint http://msdn.microsoft.com/en-us/library/office/dn423226.aspx.
- .NET Client Object Model
- Silverlight Client Object Model
- REST service endpoints
- Server Object Model
To utilize this feature on a non-SharePoint site, I am going to focus on using the .NET Client Object Model inside a .NET Web Application.
First thing we need to do is get the assemblies and include references to them in the Visual Studio project. The assemblies needed are located in the %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\15\ISAPI directory. You will need the following 3 files:
Once these are in the project you will have access to a very powerful set of classes and methods to access external SharePoint servers from within your application. To perform searches against the SharePoint farm we’ll utilize the SearchExecutor and KeywordQuery classes, and get back a ResultTable containing our results.
We can run a quick search test using the following code segments, with the appropriate replacements with your own info where necessary:
public ResultTable GetSearchResults(String queryText)
using (ClientContext context = new ClientContext(“http://yourSharePointsite/”))
context.Credentials = new System.Net.NetworkCredential(“username”, “password”, “domain”);
SearchExecutor lSearch = new SearchExecutor(context);
KeywordQuery lQuery = new KeywordQuery(context);
lQuery.RowLimit = 30;
lQuery.QueryText = queryText;
ClientResult lResultTables = lSearch.ExecuteQuery(lQuery);
ResultTable result = lResultTables.Value;
In the above code segment we’re first getting the client context of the SharePoint site, doing so in a using block so that resources are freed up for us after we’ve completed the task. We need to provide the credentials for a SharePoint account that can perform the search and create our search query. Nothing has really happened yet at this point until we call the ExecuteQuery method for the context. The Client Object Model works in batches, to help minimize the amount it times we go back and forth from the server. So even though we’ve specified to execute the search query from the SearchExecutor class, it’s only queued up at this point until call the ExecuteQuery method from the main context.
Plugging in your own servers URL, credentials, and calling the function with your search term, you should receive a ResultTable containing the top 30 search results that match your terms. These will be un-scoped, farm-wide results from the Search Service Application associated with the SharePoint site URL you provided.
To limit the scope to a Result Source, such as what was setup in Part 1 of this post, we can use the SourceId member of the KeywordQuery class. The SourceId is the Guid, not the Name, of the Result Source you’d like to use, however. So we need to dig up that Guid. Unfortunately, the Client Object Model does not have a way of querying for Result Sources. In other words, we can’t simply use the name of the result source to look up it’s Guid in the same fashion we would be able to do using the Server Object Model API. If you go back to Central Administration, Search Service Application, Result Sources, and edit the Result Source(s) you want in your app, you can find the SourceId up in the URL as one of the QueryStrings. The Guid here is URL encoded, so after copying it you’ll also need to replace all of the %2D codes you find into hyphens. (e.g. 71C9E048%2D2AED%2D4DF9%2DA305%2DE870E01AA974 to 71C9E048-2AED-4DF9-A305-E870E01AA974)
We can change the method to then look more like this:
public ResultTable GetSearchResults(String queryText, Guid resultSourceId)
if (resultSourceId != null)
lQuery.SourceId = resultSourceId;
lQuery.QueryText = queryText;
That’s basically all there is to performing some simple queries against the SharePoint server from the Client Object Model, there’s not really much to the SharePoint side of it. If you’re starting from scratch there’s still a lot of work to be done creating a method for users to enter their search terms and a mechanism for displaying the results contained in the returned ResultTable to the user.
Here are a few things to consider and/or create if you haven’t done already:
Results Page – Use ListView, GridView, Repeater, etc. Whatever you prefer. You can roll your own as well, though why reinvent the wheel?
Paging Cursor – Returning all results found could result in long page loads. I limited results to 30 in the example above, but you can utilize the .StartRow and .RowsPerPage properties of the KeywordQuery class to handle which page you want to look at.
Dedicated Reader Account – Use a dedicated account that has Full Read permissions on the SharePoint server for access via the Client Object Model.
Variablize Settings – Variablize as much as possible. Make it easy to change RowsPerPage, possibly even by the user via a dropdown control. Consider using QueryString variables on the results page for the search queries (e.g. http://site/results.aspx?k=my%20search&rows=15&start=1). This gives you some additional flexibility and allows searches to be bookmarked. Use the web.config for storing a lot of the settings, such as your SharePoint URL, the access account (don’t forget to encrypt that password!), the Guid(s) for the Result Source(s) your app will use, etc.