自定义搜索控件

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/.

自定义搜索控件
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.

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

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 associates 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, of 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.

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.

 

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.

'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 sample code in this article is available for download.
上一篇:配置vi 作为编程IDE好工具


下一篇:SqlDataReader和SqlDataAdapter 区别