ControlFreak
LANGUAGES:
VB.NET | C#
ASP.NET
VERSIONS: 2.x
Search Box
Master the Art of Search with this Custom Control that Provides
the Ability to Search Your Site, Other Sites, or the Entire Web
By Steve C. Orr
Every respectable Web site of significance needs to
provide search capabilities so users can quickly find the information they
seek. But how does a Web developer provide such functionality? There are myriad
ways one might go about this. For example, if all the content is stored within
SQL Server, its full text searching capabilities may be of use. But because
that s frequently not an option, it s not too difficult to dream about creating
a custom system that matches keywords to pages. But why reinvent the wheel? If
your Web site is publicly available on the Internet, odds are it has already
been thoroughly indexed by Google, MSN Search, and any number of other search
engines.
Leave It to the Professionals
The custom SearchBox control I ve created harnesses the
power of Google and MSN Search to provide your Web site with all the searching
muscle it needs. The SearchBox control, shown in Figure 1, is capable of using
a couple different techniques to do the searches, depending on how you
configure it.
Figure 1: The SearchBox custom
control can return search results for a specific Web site or the entire Web.
The first and simplest technique builds an appropriate URL
string and redirects the user to it. At this point the search is handed off to
Google or MSN Search, whichever has been selected in the control s
SearchProvider property. For example, if searching the Web for information
about towels, the user could be redirected to the following URL:
http://search.msn.com/results.aspx?q=towels
If the user wanted to search only MSDN for information
about Babel Fish, this URL could be used:
http://www.google.com/search?q=babel+fish+site%3Amsdn.microsoft.com
Luckily, both Google and MSN Search use similar query
strings, so the same code can be used to build the query string no matter which
search site is being used.
To use this Firefox-compatible SearchBox control to return
search results for a specific site (such as your Web site), set its
SearchSiteOnly property to True and set the SearchSite property to the public
URL of the Web site. If the SearchSiteOnly property is set to False, the
SearchSite property will be ignored and the entire Internet will be searched
for the word(s) in the Text property. To allow the users to choose whether they d
like to search the entire Web or a specific site, make sure the
ShowSearchOptions property is set to True. You can also configure the text that
will be displayed for both of these radio buttons with the SearchTheWebText
property and the SearchSiteText property.
The ButtonBelow property specifies whether the Search
button should appear beside the search TextBox or below it. The ButtonText
property lets you configure the text that appears on the button.
All these options to configure the appearance of the
control are nice, but you don t even have to show the control to use it. You
could set its visible property to False, configure some of the properties
described above, and call the SearchBox s Search method to kick off the search.
When the Search button is clicked (or the control s Search
method is called) the user will be forwarded to the standard Google or MSN
Search Web site with the results immediately displayed, as shown in Figure 2.
Figure 2: One way to use the
SearchBox is to have it redirect the user and their search request to Google s
or MSN Search s standard results page.
This approach works well, and gives the user great results
in a hurry. The only downside is that it requires the user to leave your site
to get the search results. Web developers that are trying to increase traffic
tend to cringe at the thought of sending users away, even if it s just for a
quick search that sends them right back into their site. If only there were a
good way to get the search results on the server and then output the results
into one of your own pages ...
MSN Search Web Services
Luckily, both Microsoft and Google have introduced Web
services that we can call to get search results via code. I ve chosen to take
advantage of Microsoft s Web service for this version of the SearchBox control
because it provides more features than Google s and has less restrictive
terms of use. And have you noticed how much MSN Search has improved recently? It
looks like Google may have some serious competition in the search arena, after
all.
The SearchBox encapsulates the complexities of calling the
MSN Search Web Service. If you choose to use this technique, you need to set
the SearchBox s SearchProvider property to MSNWebService. You also need to set
the MSNApplicationID property to the ID you got free from Microsoft. To get an
ID, or to learn more about the MSN Search Web Service, visit http://msdn.microsoft.com/msn/gettingstarted/searchstart/.
Now when the user clicks on the Search button, the control
will call the Web service, retrieve the search results, and raise a
SearchResultsReady event to the page. A DataTable will be passed as a parameter
to this event, allowing you to do whatever you wish with the results. Figure 3
shows a basic page that received search results from a SearchBox control and
displayed the results in a GridView control using almost no code:
Protected Sub SearchBox1_SearchResultsReady(ByVal _
SearchResults As
System.Data.DataTable) _
Handles
SearchBox1.SearchResultsReady
GridView1.DataSource =
SearchResults
GridView1.DataBind()
End Sub
Figure 3: This page only required a
couple lines of code to query the MSN Search Web Service and display the
results in a GridView.
Many Web sites prefer to have some kind of search textbox
on nearly every page, and then display the results on a specific search page. That s
where the PostBackURL property comes in. Set this property to the URL of your
special search page; then, in the code behind of that search page, use a couple
lines of code to receive the posted values and execute the search:
Protected Sub Page_Load(ByVal sender As Object, _
ByVal e As
System.EventArgs) Handles Me.Load
If
Request("SearchBox1$text") IsNot Nothing Then
SearchBox1.Text =
Request("SearchBox1$text")
SearchBox1.Search()
End If
End Sub
That s about all you need to know to start using the
SearchBox control, which is available for download (see end of article for details).
An overview of the unique properties, events, and methods are shown in Figure
4. Simply drag the SearchBox.dll into your Visual Studio 2005 toolbox, then
drag it onto any Web form(s) and you should be good to go.
|
Unique SearchBox
Members
|
Description
|
|
ButtonBelow property
|
This property specifies whether the Search button should
appear beside the search textbox or below it.
|
|
ButtonText property
|
This property specifies the text that should appear on
the Search button.
|
|
MSNApplicationID property
|
Set this to the application id Microsoft gave you.
|
|
PostBackURL property
|
Set this property to have the control post to another
page to display the results.
|
|
SearchProvider property
|
Set this to Google, MSN, or MSNWebService to use the
associated search technique.
|
|
SearchSite property
|
If you d like to search only one specific Web site (such
as your Web site), put the URL of that public Web site into this property.
|
|
SearchSiteOnly property
|
Set this property to True to only search the site
specified in the SearchSite property.
|
|
SearchSiteText property
|
Set this property to the text that you d like to be
displayed for the Search This Site radio button.
|
|
SearchTheWebText property
|
Set this property to the text that you d like to be
displayed for the Search The Web radio button.
|
|
ShowSearchOptions property
|
Set this property to True to display the radio buttons,
or False to hide them.
|
|
SearchResultsReady event
|
This event provides a DataTable filled with the results
from the MSN Search Web Service.
|
|
Search method
|
Call this method to initiate the search without
requiring the Search button to be clicked.
|
Figure 4: The
SearchBox control provides a dozen members to make searching quick and easy.
So How Does It Work?
The SearchBox is a custom Web server control. The easiest
way to create a custom Web server control is to first create a Web Control
Library. This may not be as easy as it sounds if you ve recently upgraded to
Visual Studio 2005, because Microsoft moved things around quite a bit. As you
can see in Figure 5, the option for a Web Control Library can be found under
the Windows category beneath your language of choice. Not a very intuitive
place to put it, in my opinion, but it s easy enough to find once you know
where it is.
Figure 5: The Web Control Library
project type is now located under the Windows category in the Visual Studio
2005 New Project dialog box.
The SearchBox class inherits from WebControl and
implements INamingContainer. Composition is used for this control (instead of
Rendering), meaning essentially that, internally, controls are instantiated
from within the CreateChildControls event. The source code for most of the
properties is fairly boilerplate, so I ve only listed a few of the more interesting
ones in Figure 6.
<Bindable(True), Category("Appearance"), _
Description("Shows/Hides the search option radio
buttons"), _
DefaultValue(True)> _
Public Property ShowSearchOptions() As Boolean
Get
If
ViewState("ShowSearchOptions") IsNot Nothing Then
Return _
Convert.ToBoolean(ViewState("ShowSearchOptions"))
Else
Return True
'default
End If
End Get
Set(ByVal value As
Boolean)
ViewState("ShowSearchOptions") = value
End Set
End Property
Public Enum SearchProviderEnum
MSN = 0
Google = 1
MSNWebService = 2
End Enum
Dim _spe As SearchProviderEnum
<Bindable(True), Category("Behavior"),
DefaultValue(0), _
Description("Which search method to use")> _
Public Property SearchProvider() As SearchProviderEnum
Get
Dim s As String =
CStr(ViewState("SearchProvider"))
If s Is Nothing
Then
Return _spe
Else
Select Case
Convert.ToInt32(s)
Case 0
Return
SearchProviderEnum.MSN
Case 1
Return
SearchProviderEnum.Google
Case 2
Return
SearchProviderEnum.MSNWebService
End Select
End If
End Get
Set(ByVal value As
SearchProviderEnum)
_spe = value
ViewState("SearchProvider") =
value
End Set
End Property
Figure 6: The
source code for a few of the more interesting SearchBox properties.
The ShowSearchOptions property is fairly standard,
including a few attributes to make the design time experience friendlier. ViewState
is used to ensure values are stored between page postbacks. The
SearchProviderEnum enumeration is used by the SearchProvider property to allow
the developer to select Google, MSN, or MSN s Web service.
The control is essentially rendered as a TextBox, Button,
and two RadioButtons. These child controls are created and configured from
within the overridden CreateChildControls event, as shown in Figure 7.
Private WithEvents _txt As TextBox
Private WithEvents _radio1 As RadioButton
Private WithEvents _radio2 As RadioButton
Private WithEvents _btn As Button
Protected Overrides Sub CreateChildControls()
MyBase.CreateChildControls()
'create a container for
all the controls
Dim pnl As New Panel()
pnl.ToolTip = Me.ToolTip
pnl.CssClass =
Me.CssClass
pnl.BackColor =
Me.BackColor
pnl.ForeColor =
Me.ForeColor
pnl.SkinID = Me.SkinID
'create the textbox
& add it to the container
_txt = New TextBox
_txt.Text = Me.Text
_txt.ID =
"text"
pnl.Controls.Add(_txt)
'create the button
_btn = New Button
_btn.Text =
Me.ButtonText
_btn.PostBackUrl =
Me.PostBackURL
_btn.ID =
"button"
pnl.DefaultButton =
_btn.ClientID
If Me.ButtonBelow =
False Then pnl.Controls.Add(_btn)
pnl.Controls.Add(New
LiteralControl("<br/>"))
'create the search
site/web radio buttons
If Me.ShowSearchOptions
Then
_radio1 = New
RadioButton
_radio1.Text =
Me.SearchSiteText
_radio1.GroupName =
"Search"
_radio1.Checked =
Me.SearchSiteOnly
_radio1.Style.Add(HtmlTextWriterStyle.FontSize, _
"x-small")
_radio1.ID =
"SearchSite"
pnl.Controls.Add(_radio1)
_radio2 = New
RadioButton
_radio2.Text =
Me.SearchTheWebText
_radio2.GroupName = "Search"
_radio2.Checked =
Not Me.SearchSiteOnly
_radio2.Style.Add(HtmlTextWriterStyle.FontSize, _
"x-small")
_radio2.ID =
"SearchWeb"
pnl.Controls.Add(_radio2)
pnl.Controls.Add(New
LiteralControl("<br/>"))
End If
If Me.ButtonBelow Then
pnl.Controls.Add(_btn)
Controls.Add(pnl)
End Sub
Figure 7: The
CreateChildControls method contains the code for instantiating and configuring
all the child controls.
A panel control contains all the child controls so they ll
stay together in the same area of the Web form, and a few of the base control
properties are piped through to this panel. Next, the TextBox and Button are
instantiated. The Button is configured to be the panel s default button, which
is a new feature of ASP.NET 2.0. If the Button is configured to be beside the
TextBox, then it is immediately rendered; otherwise, the rendering is delayed
until the end of this subroutine. The RadioButtons are then instantiated and
configured if the ShowSearchOptions property is set to True. Finally, all the
controls are added to the containing panel control.
Figure 8 shows the Search function, which (intuitively)
contains the meat of the logic for performing the simple search. It starts by
accepting a search string; otherwise, it uses the search string that was
previously supplied to the Text property. If the control was configured to use
the MSN Web Search Service, then control is handed off to another function
(listed in Figure 9) and an event is raised with the resulting DataTable. Otherwise,
the URL and QueryString are concatenated together and the user is redirected to
that address.
Public Sub Search(Optional ByVal SearchText As String =
"")
If SearchText.Trim.Length
> 0 Then Me.Text = SearchText
If Me.Text.Trim.Length >
0 Then
If Me.SearchProvider =
_
SearchProviderEnum.MSNWebService Then
Dim dt As DataTable
dt =
GetMSNWebSearchWebServiceResults()
RaiseEvent
SearchResultsReady(dt)
Else
Dim sb As New
StringBuilder()
If Me.SearchProvider
= SearchProviderEnum.MSN Then
sb.Append("http://search.msn.com/results.aspx?q=")
Else
sb.Append("http://www.google.com/search?hl=en&q=")
End If
sb.Append(Context.Server.UrlEncode(_txt.Text))
If Me.SearchSiteOnly
AndAlso _
Me.SearchSite.Trim.Length > 0 Then
sb.Append(Context.Server.UrlEncode(" site:"))
sb.Append(Context.Server.UrlEncode(Me.SearchSite))
End If
Context.Response.Redirect(sb.ToString)
End If
End If
End Sub
Figure 8: The
Search method contains most of the logic for performing searches by assembling
the correct URL and QueryString and redirecting the user to it.
'Queries the MSN search web service and returns a datatable
'containing the results.
'For more info on the MSN search web service, start here:
'http://msdn.microsoft.com/msn/gettingstarted/searchstart/
Protected Function GetMSNWebSearchWebServiceResults() _
As DataTable
'initialize variables
Dim s As New MSNSearchService
Dim searchRequest As New
SearchRequest
Dim arraySize As Integer
= 1
Dim sr(arraySize) As
SourceRequest
sr(0) = New SourceRequest
sr(0).Source =
[SourceType].Web
sr(0).ResultFields =
ResultFieldMask.Title _
Or ResultFieldMask.Url
sr(0).Count = 20
'assemble the search
string
Dim SearchText As String
= Me.Text & " "
If Me.SearchSiteOnly _
AndAlso
Me.SearchSite.Trim.Length > 0 Then
SearchText += "
site:"
SearchText +=
Me.SearchSite
End If
'call the msn search web
service
searchRequest.Query =
SearchText
searchRequest.Requests =
sr
searchRequest.AppID =
Me.MSNApplicationID
searchRequest.CultureInfo
= "en-US"
Dim searchResponse As
SearchResponse
searchResponse =
s.Search(searchRequest)
'fill a DataTable with
the results
Dim dt As New DataTable
Dim dc As New
DataColumn("Title")
dt.Columns.Add(dc)
dc = New
DataColumn("Url")
dt.Columns.Add(dc)
Dim sourceResponse As
SourceResponse
For Each sourceResponse
In searchResponse.Responses
Dim sourceResults As
Result() = sourceResponse.Results
Dim sourceResult As
Result
For Each sourceResult
In sourceResults
Dim dr As DataRow =
dt.NewRow
dr(0) =
sourceResult.Title
dr(1) = sourceResult.Url
dt.Rows.Add(dr)
Next
Next
Return dt 'return the
DataTable
End Function
Figure 9: This
function calls the MSN Search Web Service, transforms the results into a
DataTable, and returns the DataTable.
After adding a Web reference to the MSN Search Web Service
(located at http://soap.search.msn.com/webservices.asmx?wsdl)
the code in Figure 9 should be able to successfully call the MSN Search Web
Service. The MSN Search Web Service is very rich in functionality, providing a
wide array of capabilities that are beyond the scope of this article. To learn
more about the MSN Search Web Service, download the MSN Search SDK, which
includes documentation and several well-commented sample applications.
Search Is King
I think you ll find the SearchBox to be a valuable
addition to your Visual Studio toolbox. No longer will you need to write custom
code to provide basic searching functionality for your Web site. This
functionality should work out of the box for most public Web sites, but I can
think of several nice enhancements for a future version of the control. For
example, you might add support for other search engines, or you might choose to
add a function to call Google s search Web service. Another option is to take
advantage of MSN s desktop search functionality, which may be useful for Web
sites that are not publicly available on the Internet (and therefore, are
unreachable by standard Web-based search engines). Google has certainly proved
that searching doesn t have to be boring. The possibilities are endless, so let
your mind wander and see what you come up with.
The full source code
for the SearchBox control is available for download.
Steve C. Orr is an
MCSD and a Microsoft MVP in ASP.NET. He s been developing software solutions
for leading companies in the Seattle
area for more than a decade. When he s not busy designing software systems or
writing about them, he can often be found loitering at local user groups and
habitually lurking in the ASP.NET newsgroup. Find out more about him at http://SteveOrr.net
or e-mail him at mailto:Steve@Orr.net.