UML软件工程组织
|
权威 Hello World 自定义搜索服务教程 |
John R. Durant Microsoft Corporation |
2003 年 11 月 12 日 适用于: 摘要:Microsoft Office 2003 应用程序中的搜索服务使“搜索”任务窗格变成一了种功能强大的搜索体验,可以直接将搜索结果数据与文档连接起来。尽管可以使用 Microsoft Office System 附带的某些已注册且随时可用的搜索服务提供程序,但您仍然可以创建自定义的搜索服务。本文介绍了引用库的工作原理以及如何创建自定义服务。 目录业务方案使用某项功能或技术之前最好了解一下它们能够带来什么样的优势。Microsoft Office System 中的“搜索”任务窗格只是供用户搜索数据。当然,通过其他途经也可以搜索数据。但此搜索环境的独到之处在于,它与用户的 Office 应用体验紧密联系在一起。图 1 显示的任务窗格使用了 Microsoft Office System 附带的即时可用的一个提供程序。用户可以将文档内容自动放置到“搜索”任务窗格中,而不是将文档内容复制并粘贴到另一个应用程序或窗体中进行搜索。这使用户能够轻松地在当前工作的环境中进行搜索。同样,返回搜索结果后,用户无需将数据从单独的窗体或应用程序复制并粘贴到目标文档中。“搜索”任务窗格支持特殊的可编程操作,因此您可以将搜索到的数据以正确的格式直接放入文档中的正确位置。 图 1:“搜索”任务窗格使用户可以快速访问有用的数据 用户不必在应用程序之间来回切换,这是一个相当大的优势。但是,更具诱惑力的是,您可以创建自己的自定义搜索服务,从而满足您的公司、部门或小组的特殊需要。此外,由于“搜索”任务窗格支持智能标记操作处理程序,因此您还可以创建自己的处理程序,以便高效地为用户执行其他任务。您可以使用智能标记操作从“搜索”任务窗格中提取数据并执行大量其他的自定义活动,例如在文档中嵌入数据、自动化其他 Office 应用、发送电子邮件等。 搜索功能概述虽然本文实际上并没有使用“Hello World”字眼,但本文的目的就是向用户介绍如何设置并运行基本的自定义搜索提供程序。首先我们来看一下整个体系结构。Microsoft Office System 中的搜索服务是传统的客户端/服务器体系结构。客户端应用程序是 Office 2003 应用程序,服务器端部分是一个 Web 服务,它处理搜索请求并返回响应。当然,最终用户并不了解这些过程,他们通过“搜索”任务窗格与 Web 服务交互。下面的图 2 显示了搜索功能的一般体系结构。 图 2:用户可以从内置提供程序或自定义提供程序列表中进行选择 整个体系结构的最重要部分或许就在于,如何才能使 Web 服务可以在 Microsoft Office System 中使用。换句话说,如果 Web 服务执行大部分工作(接收请求和返回响应),那么必须存在某种机制,可以通知 Office 应用程序 Web 服务专门用于处理来自该 Office 应用程序的请求。所以,这不是仅仅依靠 Web 服务就能完成的。Web 服务和 Office 必须同时了解请求和响应的打包和发送方式以及它们所包含的内容。这种双向理解可以通过 XML 架构来实现。 XML 架构实际上是 Office 应用程序和 Web 服务之间的通信协议。用户在用户界面 (UI) 上定义搜索条件并提交搜索请求后,Office 应用程序将使用 XML 架构的结构、数据类型以及其他规定打包搜索请求。然后 Office 应用程序使用 SOAP 消息将经过打包的请求发送到 Web 服务。由于 Web 服务要求使用 SOAP 并通过与该架构相符的方式发送消息,因此 Web 服务可以按照开发人员定义的方式打开并处理请求。然后,Web 服务将收集响应,根据架构将其打包,然后使用 SOAP 消息将其发送回 Office 应用程序。然后 Office 应用程序打开响应并在任务窗格中显示结果。 对于用户发出的每个搜索请求,都会发生这种请求/响应交换。这种交换甚至还会发生在用户开始搜索之前,因为 Office 需要与 Web 服务通信,以便在客户端计算机上注册并确保其可用。用户可以在 UI 中注册搜索提供程序,也可以通过编程方式进行注册。不管使用哪种方式,Office 应用程序都需要与 Web 服务联系,以确保可以将其用作搜索功能的一部分。为了更全面地理解注册和搜索查询的工作原理,我们需要进一步了解 Office 应用程序在与 Web 服务联系时调用的 Web 方法。 注册和查询 Web 方法要创建自定义的提供程序,需要创建一个 Web 服务。最简便的方法是使用 Microsoft Visual Studio® .NET 2003 创建一个 ASP.NET Web 服务,但也可以使用 Microsoft Visual Studio .NET 2002 创建一个 ASP.NET Web 服务,或者使用 COM 技术创建一个与 SOAP 兼容的 Web 服务。有关如何在 Visual Studio 中创建基本 Web 服务的详细信息不属于本文要讨论的内容,请参阅其他相关文章。您的服务提供了两个 Web 服务 URL:一个用于注册,另一个用于查询,二者都提供了一个 Web 方法。 注意:有关如何创建 ASP.NET Web 服务的详细信息,请参阅 Creating XML Web Services in Managed Code(英文)。 用户使用自定义搜索提供程序执行查询之前必须通知 Office 应用程序。此过程称为注册:Office 应用程序首先向 Web 服务发送请求,然后 Web 服务返回包含特殊数据集的响应。这些数据包含的详细信息随后被 Office 应用程序存储在注册表中。该搜索提供程序随后将显示在最终用户可见的提供程序列表中,如前面的图 2 所示。 用户可以在 UI 中键入提供程序的地址,Web 服务将返回在 XML 中打包的关于搜索服务的信息,如图 3 所示。 图 3:用户可以键入自定义提供程序的 URL 以下 XML 是来自自定义提供程序的响应: <?xml version="1.0" encoding="utf-8"?> <ProviderUpdate xmlns="urn:Microsoft.Search.Registration.Response"> <Status>成功</Status> <Providers> <Provider> <Message>已注册</Message> <Id>{5A1AAF54-87F0-4f1d-A2D4-AB3E5D080DE1}</Id> <Name>罗斯文数据搜索窗格</Name> <QueryPath>http://localhost/nwindrr/query.asmx</QueryPath> <RegistrationPath>http://localhost/nwindrr/registration.asmx </RegistrationPath> <AboutPath>http://localhost/nwindrr/about.aspx</AboutPath> <Type>SOAP</Type> <Services> <Service> <Id>{1698075D-E2F5-4254-87B2-7FC9E9AB0780}</Id> <Name>罗斯文源数据</Name> <Description>获取罗斯文信息</Description> <Copyright>所有内容版权所有 © 2003。</Copyright> <Display>开</Display> <Category>INTRANET_GENERAL</Category> </Service> </Services> </Provider> </Providers> </ProviderUpdate> 关键在于 Microsoft Office System 要求此 XML 按照特定的方式构造。元素必须按照特定的顺序排列,必须具有规定的名称,而且必须符合特定的数据约束条件。收到 XML 后,Office 应用程序即可注册搜索提供程序,以供用户访问。注册包括在注册表中记录某些信息。例如,上一个 XML 示例中的数据来自于一个实际的搜索提供程序响应。注册成功后,可以从以下位置找到这些数据: HKEY_CURRENT_USER\Software\Microsoft\Office\11.0\Common\Research\Sources 注册表中的此项包含一个 Office 可以连接的各种搜索提供程序的列表,每个提供程序都用一个专用 ID 列出。图 4 显示了注册表中供本文中的自定义搜索提供程序使用的部分数据。 图 4:注册表包含关于已注册搜索提供程序的信息 为了使搜索服务能够启用注册,Web 服务必须提供一个叫做 Registration 的方法。以下示例显示了此方法的实现: public string Registration( string registrationXml) { XmlDocument xdResponse = new XmlDocument(); try { string httpPath = ConfigurationSettings.AppSettings["ServerPath"].ToString() + HttpContext.Current.Request.ApplicationPath + "/"; xdResponse.Load(helpers.GetCurrentPath() + "\\xml\\RegistrationResponse.xml"); XmlNamespaceManager nsm = new XmlNamespaceManager(xdResponse.NameTable); nsm.AddNamespace("ns", "urn:Microsoft.Search.Registration.Response"); xdResponse.SelectSingleNode("//ns:QueryPath", nsm).InnerText = httpPath + "query.asmx"; xdResponse.SelectSingleNode("//ns:RegistrationPath", nsm).InnerText = httpPath + "registration.asmx"; return xdResponse.InnerXml; } catch { return ""; } 上述大部分代码用来在 Web 服务器上加载 XML 文件,该文件充当此方法的返回值的模板。代码从 Web.config 文件的 appSettings 部分检索 Web 服务器的名称,并使用该名称为 Web 方法的响应的 QueryPath 和 RegistrationPath 部分创建 URL 路径。这些路径非常重要,因为注册搜索提供程序后,Office 应用程序将使用这些路径更新注册和查询 Web 服务。 虽然您不必为注册响应使用模板(如上文所述),但是使用模板有助于避免每次调用注册方法时都从头开始构造 XML 文件。模板文件的全部内容如下所示: <?xml version="1.0" encoding="utf-8"?> <ProviderUpdate xmlns="urn:Microsoft.Search.Registration.Response"> <Status>成功</Status> <Providers> <Provider> <Message>这是一个示例搜索库</Message> <Id>{5A1AAF54-87F0-4f1d-A2D4-AB3E5D080DE1}</Id> <Name>示例搜索库</Name> <QueryPath/> <RegistrationPath/> <AboutPath/> <Type>SOAP</Type> <Services> <Service> <Id>{1698075D-E2F5-4254-87B2-7FC9E9AB0780}</Id> <Name>示例搜索库</Name> <Description>这是一个示例搜索 库</Description> <Copyright>所有内容版权所有 © 2003。</Copyright> <Display>开</Display> <Category>RESEARCH_GENERAL</Category> </Service> </Services> </Provider> </Providers> </ProviderUpdate> 有关注册响应架构中各元素的详细信息,请参阅 Microsoft Office Research Service 2003 Software Development Kit (SDK)(英文)。但是这里介绍了两个元素的优点。它们是 注意:Guidgen.exe 是作为 Microsoft Visual Studio .NET 2002 或 Visual Studio .NET 2003 一部分提供的。使用时,请选择 GUID 表达式所采用的格式,这样就不必重新键入。有关 Guidgen 工具的详细信息,请参阅知识库文章 168318 XADM:Guidgen.exe Available Only for Intel Platforms(英文)。 注册 Web 服务之后,用户就可以将请求提交给 Office 应用程序中的搜索服务了。通过 UI,用户可以指定搜索条件(如本文后面的图 5 所示)并提交查询。Office 应用程序随后将通过访问 query.asmx Web 服务调用搜索服务。此服务提供了一个叫做 Query 的方法,该方法将接受参数 queryXml <QueryPacket xmlns='urn:Microsoft.Search.Query' revision='1' build='(11.0.5329)'> <Query domain='{1698075D-E2F5-4254-87B2-7FC9E9AB0780}'> <QueryId>{AE4CDA59-C3EC-496A-B0B3-B21A55EEA0CC}</QueryId> <OriginatorId>{F6FF7BE0-F39C-4ddc-A7D0-09A4C6C647A5}</OriginatorId> <SupportedFormats> <Format revision='1'> urn:Microsoft.Search.Response.Document:Document</Format> <Format revision='1'> urn:Microsoft.Search.Response.Content:Content</Format> <Format revision='1'> urn:Microsoft.Search.Response.Form:Form</Format> </SupportedFormats><Context> <QueryText type='STRING' language='en-us' >food</QueryText> <LanguagePreference>en-us</LanguagePreference> <Requery></Requery></Context> <Range id='result'></Range> <OfficeContext xmlns='urn:Microsoft.Search.Query.Office.Context' revision='1'> <UserPreferences> <ParentalControl>false</ParentalControl> </UserPreferences> <ServiceData></ServiceData> <ApplicationContext> <Name>Microsoft Office Word</Name> <Version>(11.0.5329)</Version> <SystemInformation> <SkuLanguage>en-us</SkuLanguage> <LanguagePack>en-us</LanguagePack> <InterfaceLanguage>en-us</InterfaceLanguage> <Location>US</Location> </SystemInformation> </ApplicationContext> <QueryLanguage>en-us</QueryLanguage> <KeyboardLanguage>en-us</KeyboardLanguage> </OfficeContext> <Keywords xmlns='urn:Microsoft.Search.Query.Office.Keywords' revision='1'> <QueryText>food</QueryText> <Keyword><Word>food</Word></Keyword> </Keywords> </Query> </QueryPacket> Query 方法处理来自 Office 应用程序的搜索请求并返回一个结果。您也许已经猜到,queryXml 参数中的 XML 的结构以及返回 Office 应用程序的 XML 的结构必须与架构相符合,就像注册请求和响应也必须与明确定义的架构相符合一样。搜索服务收到查询请求后发生的操作包括获取搜索关键字、处理搜索关键字并构造一个响应,这样 Office 应用程序才能为用户返回一个搜索结果。 本文中的 Query 方法的完整实现如下所示: public string Query(string queryXml) { if ( queryXml.Length == 0 ) {return "";} string queryString; //获取当前的物理路径 string physicalPath = GetCurrentPath(); XmlDocument requestXml = new XmlDocument(); //在 XmlDocument 中加载 queryXml requestXml.LoadXml(queryXml.ToString()); //添加必要的命名空间 XmlNamespaceManager nsmRequest = new XmlNamespaceManager(requestXml.NameTable); nsmRequest.AddNamespace("ns", "urn:Microsoft.Search.Query"); nsmRequest.AddNamespace("oc", "urn:Microsoft.Search.Query.Office.Context"); //获取实际的搜索条件 queryString = requestXml.SelectSingleNode("//ns:QueryText", nsmRequest).InnerText; //为响应加载某些预先配置的 XML XmlDocument responseWrapper = new XmlDocument(); responseWrapper.Load(physicalPath + "\\xml\\ResponseWrapper.xml"); XmlNamespaceManager nsmResponse = new XmlNamespaceManager(responseWrapper.NameTable); nsmResponse.AddNamespace("ns", "urn:Microsoft.Search.Response"); nsmResponse.AddNamespace("rc", "urn:Microsoft.Search.Response.Content"); //获取匹配搜索条件的客户列表 customerData = GetCustomersList(queryString); //获得生成的 customerData XML 并将其放入响应 responseWrapper.SelectSingleNode("//ns:Range", nsmResponse).InnerXml =customerData; return responseWrapper.InnerXml; } 此方法的代码主要用于获取搜索条件,并对其执行某些操作。在本示例中,搜索条件被提交给另一个自定义进程 GetCustomersList。此进程将创建 Query 方法返回的最终响应的一部分。GetCustomersList 进程返回的内容将被放置到从搜索服务返回 Office 应用程序的全部响应的一个特定节点内。 GetCustomersList 代码将嵌入一个图像,然后调用另一个访问数据库的进程,执行一个存储的进程,并返回一个 SqlDataReader 对象。对输出进行一些基本的格式化后,该代码将遍历客户列表,在公司名称中添加一些格式标记。 private string GetCustomersList( string queryTerm) { StringWriter queryResponse=new StringWriter(); XmlTextWriter outputXmlWriter = new XmlTextWriter(queryResponse); SqlDataReader customerReader; //使用自定义进程访问数据库并获取客户列表 //将返回的客户列表放入 SqlDataReader customerReader = DBGetCustomersList(queryTerm); outputXmlWriter.WriteStartElement("结果"); outputXmlWriter.WriteStartElement("内容", "urn:Microsoft.Search.Response.Content"); //插入罗斯文图像 outputXmlWriter.WriteStartElement("Image"); //从变量中获取图像的 http 路径 outputXmlWriter.WriteAttributeString("source", httpPath + "Images/nwind_small.jpg"); outputXmlWriter.WriteEndElement(); outputXmlWriter.WriteStartElement("P"); outputXmlWriter.WriteStartElement("Char"); outputXmlWriter.WriteAttributeString("Font","arial"); outputXmlWriter.WriteAttributeString("smallCaps","true"); outputXmlWriter.WriteAttributeString("bold","true"); outputXmlWriter.WriteString("名称中包含 '" + queryTerm + "' 的客户"); outputXmlWriter.WriteEndElement(); outputXmlWriter.WriteEndElement(); //搜索条件 //列出客户之前插入一条分隔线 outputXmlWriter.WriteElementString("HorizontalRule", ""); //开始列出实际的客户 while ( customerReader.Read()) { //开始公司名称 outputXmlWriter.WriteStartElement("P"); outputXmlWriter.WriteStartElement("Char"); outputXmlWriter.WriteAttributeString("font","times"); outputXmlWriter.WriteAttributeString("light","true"); outputXmlWriter.WriteString(customerReader["CompanyName"].ToString()); outputXmlWriter.WriteEndElement(); outputXmlWriter.WriteEndElement(); //结束公司名称 } outputXmlWriter.Close(); return queryResponse.ToString(); } 最后,GetCustomersList 进程返回一个字符串,该字符串可以放入搜索服务返回 Office 应用程序的最终响应中。响应的完整 XML 如下所示: <?xml version="1.0" encoding="utf-8"?> <ResponsePacket revision="1" xmlns="urn:Microsoft.Search.Response"> <Response domain="{1698075D-E2F5-4254-87B2-7FC9E9AB0780}"> <Range> <Results> <Content xmlns="urn:Microsoft.Search.Response.Content"> <Image source= "http://localhost/nwindrr/Images/nwind_small.jpg"/> <P><Char Font="arial" smallCaps="true" bold="true"> Customers with 'mer' in their name</Char></P><HorizontalRule /> <P><Char font="times" light="true">Centro comercial Moctezuma</Char></P> <P><Char font="times" light="true">LILA-Supermercado</Char></P> <P><Char font="times" light="true">Romero y tomillo</Char></P> <P><Char font="times" light="true">Tradi??o Hipermercados</Char></P> </Content> </Results> </Range> <Status>成功</Status> </Response> </ResponsePacket> 图 5 显示了与此 XML 对应的任务窗格中的用户体验。由于本文只是一篇介绍性文章,因此并没有更详尽地讨论更有用的用户体验。最后,您可以对“搜索”任务窗格进行自定义,使用户能够在与文档并排的任务窗格中执行搜索、快速引用任务并查看结果。 图 5:从为“搜索”任务窗格定制的自定义提供程序返回的结果 此外,Microsoft Office System 中的搜索功能使开发人员能够在搜索服务返回的信息中添加特殊操作。这些自定义操作通过智能标记提供给信息工作者。借助智能标记操作处理程序,用户可以执行各种任务,例如获取附加内容、转换响应文字或启动应用程序。另一种操作可以将内容作为 XML 放入 Microsoft Office Word 2003 和 Microsoft Office Excel 2003 文档中,然后就可以使用其他文档内部操作了。 小结Microsoft Office System 中的搜索服务可以大大提高用户使用 Office 应用程序的能力。用户可以通过“搜索”任务窗格进行搜索和重新查询,并能够在复杂的任务中自动包括搜索结果数据。作为开发人员,您可以为满足您的组织、甚至是小部门和小组的特殊需要自定义搜索和引用提供程序。创建自定义搜索服务并不困难,而且一旦了解 Office 与提供程序之间共享的架构之后,您就能够得心应手地帮助用户更好地执行更多任务。 John R. Durant 负责管理 MSDN Office Developer Center(英文),他的任务是帮助开发人员使用 Office 中最新最强大的技术,以及为早期版本提供文档。由于篇幅所限,他不能在这段简历中加以详述。 |
版权所有:UML软件工程组织 |