使用 Index Server 和 .NET 创建搜索页






4.74/5 (34投票s)
将您熟悉的 ADO.NET 技术(可能还有您不熟悉的)与 Microsoft Index Server 和 ASP.NET 的强大功能和灵活性相结合,为您的网站创建简单但强大的自定义搜索页面。
引言
Index Server 发布时,其潜力显而易见。开发人员不仅可以索引文档内容,还可以轻松索引文档属性和元数据。要创建搜索页和结果页,可以使用相当简单的 IDQ 和 HTX 文件。随着 Internet Information Server (IIS) 3.0 中引入 ActiveServer Pages (ASP),Index Server 2.0 添加了服务器端辅助对象。最后,Index Server 3.0(随 Windows 2000 一起发布)添加了 OLE DB 驱动程序,以便开发人员能够以查询数据库的方式查询 Index Server。正是这项技术使得在 ASP.NET 中创建强大的自定义搜索页变得容易。
将 Index Server OLE DB 提供程序与 ADO.NET 结合使用,可以让我们将结果数据绑定到常见的 ASP.NET WebControls,如 DataGrid
、Repeater
等。这些 WebControls 的简单分页功能也是相对于之前必须自己管理结果分页的模型的优势,那时我们需要使用服务器端条件语句和多个表单来处理 POST 或 GET 请求。
本文将介绍创建 ASP.NET 查询页和结果页的技术,将数据绑定的 WebControls 添加到页面,以及实现高级查询语句,同时保护敏感内容。
在继续阅读本文之前,您应该已经熟悉 Index Server 的基本架构,可以在 Platform SDK 的 MSDN 中找到。本文将不会详细讨论这些功能。
创建搜索页
在设计搜索页之前,您需要考虑用户可以搜索哪些文档属性和元数据,以及结果如何显示。通常,用户可以输入查询来搜索所有词或任何词,或者使用布尔表达式、精确表达式,甚至自然语言表达式。用户应该能够选择其查询的表达式类型,“所有词”通常是默认选项。为用户提供一种将搜索范围限制在特定范围(例如包含单个产品或部门的目录)的方法也是很有益的。这还使您能够将搜索页用作 UserControl 的目标,该 UserControl 可以出现在每个页面的顶部,并将范围设置为匹配其父目录。您还应该让用户指定结果如何排序以及每页显示多少条。
您还需要决定如何向用户显示结果。以下是一个通用格式,也是本文稍后将使用的格式:
<a href="[VPath]">[DocTitle]</a>
[Characterization]...
<i><a href="[VPath]">[SERVER_NAME][VPath]</a> - Last Modified: [Write]</i>
知道结果的外观有助于确定使用哪个控件。您可以使用 DataList
或 Repeater
,但那样您需要自己管理分页。相反,您可能选择使用带 TemplateColumn
的 DataGrid
。使用这种方法,您可以以几乎零成本的额外分页功能实现相同的结果。
Index Server 和 ADO.NET
当 Microsoft 在 Windows 2000 中的 Index Server 3.0 中添加 OLE DB 提供程序时,它为开发人员提供了使用与查询 SQL Server、Oracle、Access 等数据库相同的 ADO 技术来查询 Index Server 的方法。这些技术在 ADO.NET 中类似,但 ADO.NET 为开发人员提供了更多功能,例如 DataSet
或断开连接的记录集。虽然 DataSet
的主键、关系和标识列等功能在本例中未使用,但值得一提。
支持 ADO 和 ADO.NET 也意味着我们可以像查询其他数据库一样,使用 SQL 语句来查询 Index Server。如果您查看 MSDN 上的 Indexing Service Reference,您会发现 Index Server 支持视图、批量语句以及您可能知道的所有基本 SQL 命令。用于从上述布局中选择字段的 SQL 语句示例如下所示:
SELECT Rank, VPath, DocTitle, Filename, Characterization, Write
FROM SCOPE('DEEP TRAVERSAL OF "/"')
WHERE NOT CONTAINS(VPath, '"_vti_" OR ".config"')
AND CONTAINS(Contents, '"keyword1" AND "keyword2"')
AND CONTAINS(DocTitle, '"keyword1" AND "keyword2"')
您可能对 SCOPE
和 CONTAINS
关键字感到陌生。SCOPE
函数允许我们将查询限制在特定的目录或目录,以及是否包含子目录。数据库参考在哪里?这在 SQL 连接字符串中是隐含的。
Provider=MSIDXS.1;Data Source=Web
CONTAINS
和 FREETEXT
predicate 在 Index Server 3.0 和 SQL Server 2000 中都可用(因为它们都使用相同的 Full-text 提供程序),并且允许用户使用布尔表达式查询特定列(甚至表)中的关键字或关键字组合。使用 CONTAINS
predicate 来搜索此类关键字的存在,或使用 FREETEXT
predicate 进行自然语言搜索。
上面的 SQL 语句是示例代码中其他查询的基础,但您可以轻松地扩展此示例来搜索在特定日期之后修改或创建的文档,特定作者的文章(无需大量工作,目前仅适用于 Office 文档),以及更多内容。您甚至可以搜索媒体文件的属性或创建自己的过滤器(请参阅 IFilter 文档)。Index Server 还会索引您的自定义 META
元素。有关使用自定义过滤器的信息,请参阅 MSDN 上的 Using Custom Filters with Indexing Service。
警告: 在设计开放式 SQL 语句时,特别是供匿名用户在 Internet 上使用的语句,请务必不要允许恶意语句破坏您的数据库和目录。Web 管理员和设计者最大的错误之一是使用诸如以下之类的语句模板:
SELECT * FROM Table1 WHERE Field1 =
然后会向语句添加一个条件。那么这种方法有什么问题呢?只需要有人输入以下之类的“术语”,您的一天就毁了:
"asdf"; DELETE FROM Table1;
认为这不太可能?再想想。大多数现代数据库都支持元数据查询,使用户能够了解关于数据库及其结构的几乎所有信息。有恶意意图的用户可能会使用几个查询,并可能删除您所有表中的所有数据,甚至删除表本身。因此,请务必小心设计您的 SQL 语句模板。由于 Index Server 支持以分号 (";") 分隔的批量查询,我删除了任何分号,因此语句 “DELETE FROM
Table1” 将不超过三个关键字用于搜索。这是一种非常基本的方法,还有更好的方法,例如更高级的解析函数,但这只是一个示例,留给您练习 - 尽管这种方法应该可以阻止绝大多数情况。
您还应该注意 WHERE
子句中的第一个条件。添加此条件将导致查询不返回包含所列术语的文件或目录的搜索结果。使用上面建议的术语并添加您自己的术语,以防止用户看到敏感文件或目录,例如应用程序的“Web.config”文件或 FrontPage 目录(如“_vti_cnf”)。虽然匿名用户可能无法直接查看这些文件或浏览这些目录,但他们可以从搜索结果中的字符化(摘要)中查看敏感信息。
将搜索结果绑定到 DataGrid
ASP.NET 中的数据绑定控件非常强大,可用于许多应用程序。在本例中,我们将上面讨论的查询返回的 DataSet
绑定到 DataGrid
,并利用其强大的分页功能让用户浏览搜索结果页面。从这一点开始,几乎所有的示例功能都以最小的开发成本提供给我们。
还记得文章开头的搜索结果模板吗?这显然不是一个列式模板,那么我们如何在 DataGrid
中实现它呢?TemplateColumn
允许我们使用 HTML 来查找字段和表达式,就像我们通常做的那样。要告诉绑定容器使用特定的表达式进行绑定,我们使用 <%# %>
数据绑定表达式语法。这样的表达式如下所示:
<asp:hyperlink runat="server"
NavigateUrl='<%# DataBinder.Eval(Container.DataItem, "VPath")%>'
><%# GetTitle(Container.DataItem)%></asp:hyperlink>
这将显示一个超链接,其目标是文档路径,链接文本是相应的文档标题或文件名。GetTitle()
是我们代码隐藏类中的一个 protected
方法,该方法确定 DocTitle
是否可用,如果不可用,则返回 Filename
。如您所见,绑定表达式不限于数据绑定表达式。有关文章开头给出的结果显示格式的完整示例,请参阅示例源代码。您可以随意尝试不同的布局或添加其他列,从单个列的 BoundColumn
到自定义布局的 TemplateColumn
,如上例所示。但是,请确保将 AutoGenerateColumns
设置为 false
,否则所有选定的字段都会在您用户定义的绑定列之前和之外输出。
分页结果
如前所述,使用 DataGrid
数据绑定控件来显示我们的搜索结果,可以为我们提供几乎免费的分页技术。之前的 ASP 解决方案,甚至使用 IDQ/HTX 文件,要么迫使我们使用大型 GET 查询(这会受到浏览器地址栏长度限制的影响),要么在我们的页面中包含多个表单。ASP.NET 只允许一个页面有一个服务器端表单,尽管这些之前的技术可以通过客户端表单和页面输出语句来实现。这可能很乏味,而 ASP.NET 为我们提供了更好、面向对象的选项。
要处理数据分页,请将 AllowPaging
设置为 true
,并为 DataGrid.PageIndexChanged
事件添加新的事件处理程序,然后输入以下代码,将 dgResultsGrid
替换为您使用的任何控件名称:
private void dgResultsGrid_PageIndexChanged(object source,
DataGridPageChangedEventArgs e)
{
this.dgResultsGrid.CurrentPageIndex = e.NewPageIndex;
this.Search(); // A private method that actually starts the search.
}
这将根据 DataGrid.CurrentPageIndex
乘以 DataGrid.PageSize
来设置绑定源的起始位置。
摘要
使用您已经知道并用于从数据库检索结果的 ADO.NET 技术,您可以轻松构建快速、强大的搜索页面,而无需像以前那样繁琐的工作。Index Server 的 OLE DB 提供程序为您提供了极大的灵活性,以及增加了更多出色功能的附加函数和谓词。使用您已经熟悉的易于使用的数据绑定控件,如 DataGrid
,您可以快速且无需大量代码地显示这些结果。将这三项技术与上面讨论的简单技术以及示例源代码相结合,可以在很短的时间内为您的网站提供强大的搜索功能。