Click here to Skip to main content
15,891,375 members
Articles / Web Development / ASP.NET

SharePoint Custom Search Results Page

Rate me:
Please Sign up or sign in to vote.
2.95/5 (11 votes)
29 Jun 200611 min read 214.2K   1.4K   33  
An article on how to create a custom search results page in a Windows SharePoint Services site.
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%@ Page Language="C#" EnableViewState="true" EnableViewStateMac="false"  ValidateRequest="False" %>
<%@ Import namespace="Microsoft.SharePoint.Utilities" %>
<%@ Import namespace="System.Data" %>
<%@ Import namespace="System.Collections" %>
<%@ Import namespace="System" %>
<%@ Import namespace="System.Web" %>

<!--
This page is a custom search results page.
It is a copy of searchresults.aspx, excluding the original server-side content.
There is no code-behind page.
This page expects two querystring parameters:
	SearchString (urlencoded) - the string to search for
	TargetURL - the URL of the search page (this)
This page searches only the specified document library. It invokes its own search.
Results are displayed in a sortable datagrid.
Datagrid columns are added at runtime, using the columns in an existing document library view ("Search Results").
A hidden column, containing the plain text title, is used as the sort expression for the title column, since the title
column contains the URLs, and sorting by them is not correct.
-->
<HTML dir="ltr">
	<HEAD>
		<Title id="onetidTitle">Content Repository Search Results</Title> 
		<!-- _lcid="1033" _version="11.0.5510" _dal="1" -->
		<!-- _LocalBinding -->
		<META Name="GENERATOR" Content="Microsoft SharePoint">
		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
		<META HTTP-EQUIV="Expires" content="0">
		<script src="owsbrows.js"></script>
		<SharePoint:CssLink DefaultUrl="styles/ows.css" runat="server" id="CssLink1" />
		<SharePoint:Theme runat="server" id="Theme1" />
		<script><!--
if (browseris.mac && !browseris.ie5up)
{
    var ms_maccssfpfixup = "styles/owsmac.css";
    document.write("<link rel='stylesheet' Type='text/css' href='" + ms_maccssfpfixup + "'>");
}
//--></script>
		<script src="ows.js"></script>
		<SharePoint:CustomJSUrl runat="server" id="CustomJSUrl1" />
		<script>
	if(typeof(msnwebColorCode) == "undefined"){ //if the site has no colorcode.js file, set the following manually
		var msnwebColorCode = "lb"; //default to light blue if no color is set
		var msnwebSiteType = "site";  //portal or team site
		var msnwebTopNavXML = "/msnweb_topnav.xml";  //the location for the XML data to populate the top nav bar
		var msnwebNeedToXML = "/msnweb_needto.xml";  //the location for the XML data to populate the need to list
		document.write("<link rel='stylesheet' type='text/css' href='/_msnw/css/styles_" + msnwebColorCode + ".css'>");
	}
	document.write("<link rel='stylesheet' type='text/css' href='/_msnw/css/msn_default.css'>");
	var msnwebHeaderOnly = true;
	</script>
<script src="/_msnw/menu.js" type="text/javascript"></script>
<link type="text/xml" rel='alternate' href="_vti_bin/spdisco.aspx" />
			
<script language="C#" runat="server">
//This method contains the code needed to dynamically create the DataGrid columns from the fields found 
//in the "search results" view. 
void Page_Init(Object Sender, EventArgs e)
{
	//Get reference to site from querystring
	string url = Request.QueryString["Target"].ToString();
	SPSite siteCollection = new SPSite(url);
	SPWeb CRsite = siteCollection.OpenWeb();
	
	//get reference to Content Repository Doc Lib
	SPListCollection AllLists = CRsite.Lists;
	AllLists.IncludeRootFolder = true;
	SPList ContRep = AllLists["Content Repository"];
	
	//get field objects from Content Repository - needed to obtain display name of fields
	SPFieldCollection ListFields = ContRep.Fields;

	//get field names used in search results view (these are "internal" names, not display names)
	SPView SRView = ContRep.Views["Search Results"];
	SPViewFieldCollection SRViewFields = SRView.ViewFields;
	System.Collections.Specialized.StringCollection InternalViewFldNames = SRViewFields.ToStringCollection();
	
	//using internal names, build the datagrid columns, in field order
	BoundColumn C = null;
	string str="";
	for (int i=0; i< InternalViewFldNames.Count; i++)
	{
		C = new BoundColumn();
		if (i>0) //no header for doc icon
		{
			C.HeaderText = ListFields.GetFieldByInternalName(InternalViewFldNames[i]).Title;	//this is the DISPLAY name
            str += "Column: " + C.HeaderText + "|";
            C.SortExpression = InternalViewFldNames[i];
            str += "Sort by: " + InternalViewFldNames[i] + "<br>";
			//change "name" column to be "file name"
			if (C.HeaderText == "Name")
				C.HeaderText = "File Name";
			if (C.HeaderText == "Title")
				C.SortExpression = "SortByTitle";
		}
		
		C.DataField = InternalViewFldNames[i];
		C.ItemStyle.VerticalAlign = VerticalAlign.Top;
		DataGrid1.Columns.Add(C);
		//str += InternalViewFldNames[i] + " ";
	}	
	//add hidden column for sorting by title (NOT URL of title!)
	C = new BoundColumn();
	C.HeaderText = "SortByTitle";
	C.SortExpression = "SortByTitle";
	C.DataField = "SortByTitle";
	C.Visible = false;
	DataGrid1.Columns.Add(C);
	
	//lblNoResults.Text = str;

}//end page_init

//simple page load method - calls BindData initially (no sort order)
void Page_Load(Object Sender, EventArgs e) 
{	
	if (!Page.IsPostBack)
	{
		BindData("");	
	}//end if not postback
        
}//end pageload

//This is the workhorse of the page. It does the following:
//	invokes the search using string from querysting
//	builds a datatable from the search results items
//	creates a dataview from the datatable
//	applies the sort Order (if any)
//	binds dataview to datagrid
//Parameter: sortOrder (string) - if not empty, contains the datacolumn name to perform the sort on
void BindData(string sortOrder)
		{
			//create view and table objects
			DataView ResultsView = new DataView();
			DataTable ResultsTable = new DataTable();
			DataRow ResultsRow;
			
			//create lists to house search result info
			ArrayList DocURLs = new ArrayList();
			ArrayList IconURLs = new ArrayList();

			//Get reference to site to search:
			string url = Request.QueryString["Target"].ToString();
			SPSite siteCollection = new SPSite(url);
			SPWeb CRsite = siteCollection.OpenWeb(); 

			//get search string from querystring
			string SearchString = Request.QueryString["CRSearchString"].ToString();
			SearchString = Server.UrlDecode(SearchString);
			lblSearchString.Text = SearchString;

			//Invoke document search of content repository with string passed in
			SPSearchResultCollection Results = CRsite.SearchDocuments(SearchString);
            
            int ActualResultCount = 0;
			if (Results.Count != 0)
			{
                //place URL of each doc in arraylist for later processing - only keeping those from "Content Repository" doc library
                string itemURL = ""; 
				foreach(SPSearchResult item in Results)
				{
                    itemURL = item.Url.ToString();
                    if (itemURL.IndexOf("/sitename/documentlibraryname/") > 0)
                    {
                        //increment actual result count
                        ActualResultCount++;
                        
                        //save document URL
                        DocURLs.Add(itemURL);

                        //save doc icon URL
                        IconURLs.Add(item.IconUrl.ToString());
                    }
				}//end foreach item in search results collection
                //lblNoResults.Text = s;
            }//end if
    
            if (ActualResultCount > 0)
            {
				//get reference to Content Repository Doc Lib
                SPListCollection AllLists = CRsite.Lists;
				AllLists.IncludeRootFolder = true;
				SPList ContRep = AllLists["Content Repository"];
				
				//get field objects from list (which contain the display names of the fields)
				SPFieldCollection ListFields = ContRep.Fields;
		
				//get field names used in search results view (these are "internal" names, not display names)
				SPView SRView = ContRep.Views["Search Results"];    //"Search Results" is the name of the doc lib view
				SPViewFieldCollection SRViewFields = SRView.ViewFields;
				System.Collections.Specialized.StringCollection InternalViewFldNames = SRViewFields.ToStringCollection();

				//string s="";
				//process each view field, building results table columns 
				for (int j=0; j< InternalViewFldNames.Count; j++)
				{
					ResultsTable.Columns.Add(new DataColumn(InternalViewFldNames[j], typeof(string)));
					//s += InternalViewFldNames[j] + " ";
				}
                //add the hidden column
				ResultsTable.Columns.Add(new DataColumn("SortByTitle", typeof(string)));
				//lblNoResults.Text = s;
				
				string strURL="";
				string strField="";
				string ID="";
				SPListItem ThisItem = null;

				//for each doc url in array, get document object and build results row
				for (int k=0; k<DocURLs.Count; k++)
				{
								
					//using URL, get id of item to retrieve item object
                    //URL is in this format: http://server/sitecollection/currentsite/documentlibraryname/Forms/DispForm.aspx?ID=nn 
					strURL = DocURLs[k].ToString();
                    //extract only the digits after "?ID=" or "&ID="
                    Regex exp1 = new Regex(@"[\?|&]ID=([0-9]+)");
                    if (!exp1.IsMatch(strURL))  //ignore any file w/o and ID, since it's not a list item (some pages in forms library might match)
                    {
                        continue;
                    }
                    ID = exp1.Matches(strURL)[0].Groups[1].Value;
                    
                    //get the item object using the ID just obtained
                    ThisItem = ContRep.GetItemById(Convert.ToInt32(ID));

                    //create new row for item
                    ResultsRow = ResultsTable.NewRow();
                   
				
					//for each view field name, fill results row with item metadata
					for (int j=0; j<InternalViewFldNames.Count; j++)
					{
                        ResultsRow[InternalViewFldNames[j]] = ThisItem[ListFields.GetFieldByInternalName(InternalViewFldNames[j]).Title];
						strField = ResultsRow[InternalViewFldNames[j]].ToString();
						//some fields may have "x;#" at the beginning - strip it off as well as any others
						if (strField.IndexOf("#") >=0)
						{
							strField = strField.Substring(strField.IndexOf("#")+1); //get's the first occurrence
                            strField = strField.Replace(";#", ";"); //get rid of any other #'s, leaving the ";"
							ResultsRow[InternalViewFldNames[j]] = strField;
						}
						
					}

					//customize "special rows": 
					//make icon row display an image
					ResultsRow["DocIcon"] = "<a href='" + strURL + "'><img src='" + IconURLs[k].ToString() + "' border=0></a>";
					
					
					//make doc name link to doc property page
					ResultsRow["Title"] = "<a href='" + strURL + "'>" + ThisItem["Title"] + "</a>";
					ResultsRow["SortByTitle"] = ThisItem["Title"].ToString();
					
					//add row to table
					ResultsTable.Rows.Add(ResultsRow);					 
				}//end for each docURL

				//put results into a dataview
				ResultsView = new DataView(ResultsTable);
				
				//sort, if needed
				if (sortOrder != "")
					{
					ResultsView.Sort = sortOrder;
					}
				
				//bind to grid
				DataGrid1.DataSource = ResultsView;
				DataGrid1.DataBind();
	
				//set instructions label
				lblGridInstructions.Text = "Click a column header to sort the results by that column.";
	
			}//end if we have results
			else
			{
				lblNoResults.Text = "<p>No results were found.</p>";
				lblGridInstructions.Text = "";
			}
		}//end BindData

//DataGrid sort event handler - fires when user clicks a column name.
//The event arg contains the datacolumn name which is passed to the BindData() method
void DataGrid1_Sort(object source, System.Web.UI.WebControls.DataGridSortCommandEventArgs e)
{
   
	BindData(e.SortExpression);
	
}

</script>

<script language=javascript>
//This function invokes a new search, with the value in the textbox
function DoCRSearch()
{
    
    //get value of textbox 
	var obj = document.getElementById("CRSearchString");
	var strSearch = obj.value;
	
	//make sure we don't have empty string
	if (strSearch == "")
	    alert("Please enter a search term.");
	else
	{    	
    	//URL encode search string
	    strSearch = escape(strSearch);

	    //build target URL for site
        var loc = document.location.href;
        var baseURL = loc.substring(0,loc.lastIndexOf("/"));
	    var strTarget = baseURL + "/default.aspx";

	    //redirect to search page, adding on target URL and search string as querystring parameters
	    document.location.href = baseURL + "/_layouts/1033/searchresultsCR.aspx?CRSearchString=" + strSearch + "&Target=" + strTarget;
    }//end else

}//end function
</script>

	</HEAD>
	<BODY marginwidth="0" marginheight="0" scroll="yes">
		<TABLE class="ms-main" CELLPADDING="0" CELLSPACING="0" BORDER="0" WIDTH="100%" HEIGHT="100%">
			<!-- Banner -->
			<%
string alternateHeader = SPControl.GetContextWeb(Context).AlternateHeader;
if (alternateHeader == null || alternateHeader == "")
{
%>
			<TBODY>
				<TR> 
                  <TD COLSPAN=3 WIDTH=100%>
                  <!--Top bar-->
   	                <table cellpadding="0" cellspacing="0" border="0" width="100%" height="100%">
		                <tr valign="top">
			                <TD WIDTH=100% height="26" id="MSNWebTopNavBar">
				                <script src="/_msnw/topnav.js"></script>
			                </TD>
		                </tr>
	                </table>
                  </TD>  
                </TR>
				<%
}
else
{
    Server.Execute(alternateHeader);
}
%>
				<tr> 
        <td colspan=3 class="ms-titleareaframe"> 
            <div class="ms-titleareaframe"> 
            <table width=100% border=0 class="ms-titleareaframe" cellpadding=0 cellspacing=0> 
            <tr> 
            <td style="padding-bottom: 0px"> 
            <table style="padding-top: 0px;padding-left: 2px" cellpadding=0 cellspacing=0 border=0> 
            <tr> 
            <td align=center nowrap style="padding-top: 4px" width="108" height="46"> 
                <img ID=onetidtpweb1 src="/_layouts/images/search.gif" alt="Icon" height="49" width="49"> </td> 
            <td><IMG SRC="/_layouts/images/blank.gif" width=22 height=1 alt=""></td> 
            <td nowrap width="100%" style="padding-top: 0px"> 
                <table cellpadding=0 cellspacing=0> 
                    <tr> 
                        <td nowrap class="ms-titlearea"> 
                            <a href="../../"><SharePoint:ProjectProperty Property="Title" runat="server"/></a> 
                        </td> 
                    </tr> 
                    <tr> 
                        <td ID=onetidPageTitle class="ms-pagetitle">Content Repository Search Results<!-- --></td> 
                    </tr> 
                 </table> 
              </td>  
              </tr> 
              </table> 
              <table cellpadding=0 cellspacing=0 border=0 width=100%> 
                <tr> 
                    <td class="ms-titlearealine" height=1 colspan=5><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></td> 
                 </tr> 
              </table> </td> </tr> </table> </div> </td> </tr>
				<!-- Navigation -->
				<TR>
					<TD valign="top" height="100%" class="ms-nav">
						<TABLE height="100%" class="ms-navframe" CELLPADDING="0" CELLSPACING="0" border="0" width="126">
							<tr>
								<td valign="top" width="100%">&nbsp;</td>
								<td valign="top" class="ms-verticaldots">&nbsp;</td>
							</tr>
						</TABLE>
					</TD>
					<!-- Contents  -->
					<td width="90%" valign="top" class="ms-descriptiontext">
					<!--CUSTOM CODE -->
						<p>&nbsp;</p>
						<asp:Label ID=lblError Font-Bold=True ForeColor=Red></asp:Label>
						<p><b>You searched for: </b>
							<asp:Label ID="lblSearchString" Runat="server"></asp:Label></p>
						<asp:Label ID="lblNoResults" Runat="server"></asp:Label>
						<br><b>New search: </b>
					<input type=text name=CRSearchString id=CRSearchString>
					<input type=button name=btnSubmit value="Submit" onclick="DoCRSearch()">
						<form name="GridForm" id="GridForm" runat="server">
							<p><asp:Label ID="lblGridInstructions" Runat="server"></asp:Label>
								<asp:DataGrid id="DataGrid1" runat="server" AllowSorting="True" AutoGenerateColumns="false" AlternatingItemStyle-BackColor="Silver"
									HeaderStyle-Font-Bold="true" CssClass="ms-descriptiontext" OnSortCommand="DataGrid1_Sort"></asp:DataGrid></p>
						</form>
					<!--END OF CUSTOM CODE-->
					</td>
					<!-- Close the TR from formbar.inc -->
				</TR>
			</TBODY></TABLE>
	</BODY>
</HTML>

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
Kris Rudin is a senior developer with Ascentium corporation, with 10 years of experience including both web and Windows client software development.

Comments and Discussions