In addition to making it easy for the users to execute ad hoc site searches, it may also be valuable to dynamically display a listing of related web sites. To provide this feature, one approach would be to create a Web Part that allows the site owner to specify some related keywords, and then perform the Site Directory search and display a list of relevant sites.
The Related sites Web Part will be added to the previously created SPBlueprints.WebParts
project created in Chapter 2, Building an Out of Office Delegation Solution.
To add the additional Web Part:
SPBlueprints.WebParts
project in Visual Studio 2010. RelatedSites.webpart file
, and add in the custom properties as shown in the following:<property name="Title" type="string">Related Sites</property> <property name="Description" type="string">SPBlueprints - The Related Sites web part will search for sites with matching keywords.</property> <property name="SearchProxyName" type="string">Search Service Application</property> <property name="SearchScopeName" type="string">Site Directory</property> <property name="DisplayLimit" type="int">5</property> <property name="KeywordList" type="string">sites</property>
RelatedSites.cs
file and add in the following references:using System.Collections; using System.Data; using System.Text; using Microsoft.SharePoint.Administration; using Microsoft.Office.Server.Search; using Microsoft.Office.Server.Search.Query; using Microsoft.Office.Server.Search.Administration;
private string _searchProxyName; [WebBrowsable(true), Category("Configuration"), WebDisplayName("Search Proxy Name"), WebDescription("Please provide the name of your Search Service Application."), Personalizable(PersonalizationScope.Shared)] public string SearchProxyName { get { return _searchProxyName; } set { _searchProxyName = value; } }
private string _searchScopeName; [WebBrowsable(true), Category("Configuration"), WebDisplayName("Search Scope Name"), WebDescription("Please provide the name of your Search Scope."), Personalizable(PersonalizationScope.Shared)] public string SearchScopeName { get { return _searchScopeName; } set { _searchScopeName = value; } }
private int _displayLimit; [WebBrowsable(true), Category("Configuration "), WebDisplayName("Result limit"), WebDescription("The number of items to display."), Personalizable(PersonalizationScope.Shared)] public int DisplayLimit { get { return _displayLimit; } set { _displayLimit = value; } }
private string _keywordList; [WebBrowsable(true), Category("Configuration"), WebDisplayName("Keywords"), WebDescription("Comma delimited list of keywords"), Personalizable(PersonalizationScope.Shared)] public string KeywordList { get { return _keywordList; } set { _keywordList = value; } }
CreateChildControls()
method as shown in the following:protected Literal _output; protected override void CreateChildControls() { this._output = new Literal(); this._output.ID = "output"; this.Controls.Add(this._output); }
Display()
method that can be called from the OnLoad()
method. The method starts by defining StringBuilder
that we will use to build the output of the Web Part, and then checks to see if there are any keywords set. Since the keywords are stored within a single string property and are comma delimited, we will do a simple split command to load the values into an array. If there are no keywords, there will be no content to display.protected void Display() { StringBuilder messages = new StringBuilder(); string[] keywords = this._keywordList.Split(','), if (keywords[0] != "") {
try/catch
block here in order to handle issues related to connecting to the Search service application differently than errors returned as part of a search.try { SearchQueryAndSiteSettingsServiceProxy settingsProxy = SPFarm.Local.ServiceProxies.GetValue<SearchQueryAndSiteSettingsServiceProxy>(); SearchServiceApplicationProxy searchProxy = settingsProxy.ApplicationProxies.GetValue<SearchServiceApplicationProxy>(this.searchProxyName); // Query and Display of Web Part Catch { this.EnsureChildControls(); this._output.Text = "Error: Please specify a Search Service Application."; }
FullTestSqlQuery
and prepare the data objects.FullTextSqlQuery mQuery = new FullTextSqlQuery(searchProxy); try { ResultTableCollection resultsTableCollection; DataTable results = new DataTable();
for
loop to append the query to include a dynamic part that covers each keyword. Since we are looking for matches for any of the keywords, the OR
operator will be used, which will require that we set the scope predicate starting with the second keyword. The query can also be tailored to exclude other content in your environment as needed.mQuery.QueryText = "SELECT Title, Path, SiteName FROM SCOPE() Where "; for (int i = 0; i <= keywords.GetUpperBound(0); i++) { if (i > 0) mQuery.QueryText += " OR "; mQuery.QueryText += " (("scope" = '" + _searchScopeName + "') AND Contains('" + keywords[i] + "'))"; }
FullTextSqlQuery
properties can now be set and the query executed. The returned DataTable
object can now be checked for results to see if the list needs to be rendered.mQuery.ResultTypes = ResultType.RelevantResults; mQuery.TrimDuplicates = true; mQuery.RowLimit = DisplayLimit; resultsTableCollection = mQuery.Execute(); if (resultsTableCollection.Count > 0) { ResultTable relevantResults = resultsTableCollection[ResultType.RelevantResults]; results.Load(relevantResults, LoadOption.OverwriteChanges);
messages.AppendFormat(@"<div id='RelatedSites'><ul>"); foreach (DataRow row in results.Rows) { messages.AppendFormat(@"<li><a href='{1}'>{0}</a></li>", row["Title"].ToString(), row["Path"].ToString(), row["SiteName"].ToString()); } messages.AppendFormat(@"</ul></div>"); }
18.217.5.86