Saturday, May 10, 2008

Custom Search Web Part

If you don't like look and feel of the out-of-box Search Core Result web part, you can customize it by using a xsl stylesheet through the XSL Editor of the web part. Here is how. If you want to completly replace the search result with your own custom search web part, here is how:

Steps:
1. Open VS2008, create a project. Under the Visual C# > Web > ASP.NET Server Control. Name the project CustomSearchWebPart.
2. Add the following references to the project:

  • System.Data
  • System.XML
  • Microsoft.SharePoint
  • Microsoft.Office.Server
  • Microsoft.Office.Server.Search
3. Add the following code to the control. Note here we are inheriting WebPartPages which is the sharepoint web parts rather than the ASP.NET web parts.

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Text;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Drawing;

using System.Xml;

using System.Xml.Serialization;

using System.Data;

using Microsoft.SharePoint.WebPartPages;

using Microsoft.Office.Server;

using Microsoft.Office.Server.Search.Query;

namespace CustomSearchWebPart

{

[ToolboxData("<{0}:clsSearchQuery runat=server></{0}:clsSearchQuery>")]

[XmlRoot(Namespace = "CustomSearchWebPart")]

public class clsSearchQuery : WebPart

{

[Bindable(true)]

[Category("Appearance")]

[DefaultValue("")]

[Localizable(true)]

Button cmdSearch;

TextBox txtQueryText;

Label lblQueryResult;

DataGrid grdResults;

4. Create a textbox and a search button, add them to the web part.

protected override void CreateChildControls()

{

Controls.Clear();

txtQueryText = new TextBox();

this.Controls.Add(txtQueryText);

cmdSearch = new Button();

cmdSearch.Text = "Start Search";

cmdSearch.Click += new EventHandler(cmdSearch_Click);

this.Controls.Add(cmdSearch);

lblQueryResult = new Label();

this.Controls.Add(lblQueryResult);

}

5. I am using querystring to render the search result as well, so the page which contains this web part could be called by other pages as well.

protected override void OnPreRender(EventArgs e)

{

if (!Page.IsPostBack)

{

if (Page.Request["k"] != null)

{

txtQueryText.Text = Page.Request["k"].ToString();

}

DoSearch();

}

}

private void DoSearch()

{

if (txtQueryText.Text != string.Empty)

{

keywordQueryExecute(txtQueryText.Text);

}

else

{

lblQueryResult.Text = "You must enter a search word.";

}

}

void cmdSearch_Click(object sender, EventArgs e)

{

DoSearch();

}

6. Use KeywordQuery class to get the search result into a ResultTable. Note here I have specified the search to only return result of the Newsletters search scope.

private void keywordQueryExecute(string strQueryText)

{

KeywordQuery kRequest = new KeywordQuery(ServerContext.Current);

string strQuery = strQueryText;

kRequest.QueryText = strQuery;

kRequest.HiddenConstraints = "scope:" + "\"Newsletters\"";

kRequest.ResultTypes = ResultType.RelevantResults;

ResultTableCollection resultTbls = kRequest.Execute();

if ((int)ResultType.RelevantResults != 0)

{

ResultTable tblResult = resultTbls[ResultType.RelevantResults];

if (tblResult.TotalRows == 0)

{

lblQueryResult.Text = "No Search Results Returned.";

}

else

{

ReadResultTable(tblResult);

}

}

}

7. Load the ResultTable into a DataSet.

void ReadResultTable(ResultTable rt)

{

DataTable relResultsTbl = new DataTable();

relResultsTbl.TableName = "Relevant Results";

DataSet ds = new DataSet("resultsset");

ds.Tables.Add(relResultsTbl);

ds.Load(rt, LoadOption.OverwriteChanges, relResultsTbl);

fillResultsGrid(ds);

}

8. Create a datagrid and add it to the web part. Bind it with the search result.

private void fillResultsGrid(DataSet grdDs)

{

//Instantiate the DataGrid, and set the DataSource

grdResults = new DataGrid();

grdResults.DataSource = grdDs;

//Set the display properties for the DataGrid

grdResults.GridLines = GridLines.None;

grdResults.CellPadding = 4;

grdResults.Width = Unit.Percentage(100);

grdResults.ItemStyle.ForeColor = Color.Black;

grdResults.ItemStyle.BackColor = Color.AliceBlue;

grdResults.ItemStyle.Font.Size = FontUnit.Smaller;

grdResults.ItemStyle.Font.Name = "Tahoma";

grdResults.HeaderStyle.BackColor = Color.Navy;

grdResults.HeaderStyle.ForeColor = Color.White;

grdResults.HeaderStyle.Font.Bold = true;

grdResults.HeaderStyle.Font.Name = "Tahoma";

grdResults.HeaderStyle.Font.Size = FontUnit.Medium;

grdResults.AutoGenerateColumns = false;

HyperLinkColumn colTitle = new HyperLinkColumn();

colTitle.DataTextField = "Title";

colTitle.HeaderText = "Title";

colTitle.DataNavigateUrlField = "Path";

grdResults.Columns.Add(colTitle);

BoundColumn colAuthor = new BoundColumn();

colAuthor.DataField = "Author";

colAuthor.HeaderText = "Author";

grdResults.Columns.Add(colAuthor);

grdResults.ItemDataBound += new DataGridItemEventHandler(grdResults_ItemDataBound);

grdResults.DataBind();

Controls.Add(grdResults);

}

9. Handles the ItemDataBound event of the datagrid to perform custom actions. In this case, I replace the url column with something else.

void grdResults_ItemDataBound(object sender, DataGridItemEventArgs e)

{

if (e.Item.ItemType == ListItemType.Item e.Item.ItemType == ListItemType.AlternatingItem)

{

HyperLink h = (HyperLink)e.Item.Cells[0].Controls[0];

String url = h.NavigateUrl;

if (url.Contains(@"Lists/CompanyList/DispForm.aspx?ID="))

{

url = url.Replace(@"Lists/CompanyList/DispForm.aspx", @"Pages/CompanyProfile.aspx");

h.NavigateUrl = url;

}

}

}

}

}

10. If not strong-named, then you can deploy to the bin:

  • Add the CustomSearchWebPart.dll to Inetpub\wwwroot\wss\VirtualDirectories\sitename\bin
  • Open the web.config in Inetpub\wwwroot\wss\VirtualDirectories\sitename, add the following to the SafeControls section
    • <SafeControl Assembly="CustomSearchWebPart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" Namespace="CustomSearchWebPart" TypeName="*" Safe="True" />

11. Create the Web Part definition file. Add the following to a notepad and name it CustomSearchWebPart.dwp:

<?xml version="1.0"?>

<WebPart xmlns="http://schemas.microsoft.com/WebPart/v2">

<Assembly>CustomSearchWebPart, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=null</Assembly>

<TypeName>CustomSearchWebPart.clsSearchQuery</TypeName>

<Title>Custom Search Web Part</Title>

</WebPart>

12. Go to the page where you want to add the web part to, click to add a new web part, click the Advanced Web Part gallery and options, click the browser link and then click import to import the dwp file to the web part gallery, then add it to the page.

Reference:

Micosoft Office SharePoint Server 2007 SDK

blog comments powered by Disqus