技术开发 频道

为 SharePoint 提供 SQL Server 报表以增强团队协作


【IT168技术文档】

  假设您所在的公司有一个关键的数据库应用程序,它不断地记录新的传入信息。该数据库可能存储定单信息、销售联系人信息,或者任何其他类型的数据。现在假设,您公司内的一组员工根据有关该数据的报表(也许是月结帐单的趋势分析)进行关键的业务决策。这些报表根据定时任务创建:每日、每周或每月。听起来很熟悉吧?您的公司可能已经拥有了类似系统。差不多任何类型的公司都有可能这样。
  Microsoft® SQL Server® Reporting Services 允许用户订阅报表并将报表自动传递给用户,从而简化了这种情况。尽管这是一个有用的功能,但它只解决了更大目标的一个方面。用户在收到报表后,很可能希望不仅限于通览数据。也许他们需要为员工创建并分配任务,或者他们可能希望允许小组内的成员对数据进行建设性的讨论,或者他们可能只需要将数据合并到一个 Microsoft PowerPoint® 演示文稿中。
  问题是,系统通过电子邮件或将报表粘贴到公司内部的文件共享(这是订阅的两种现成的传递方法),从而将报表的副本传递给每个员工。这两种情况都不支持有关组内报表的协作。一个更有趣的解决方案是将报表传递给 Microsoft SharePoint® 文档库,其中的讨论和协作功能都能很容易地与报表一起使用。本文详细介绍如何创建一个自定义的 SQL Server Reporting Services 传递扩展,它会将报表存储在一个 Windows® SharePoint Services (WSS) 文档库中。
体系结构
  在我所描述的情况中,报表的时间很重要。不管用户何时查看报表,报表必须对所有用户都是一样的。因此,我不能依赖于这样的模型:每个用户在他们碰巧访问 SharePoint 站点时按需运行报表。(使用 SQL Server 2000 Reporting Services Service Pack 2 中新增的报表查看器 Web 部件可以很轻松地实现按需解决方案,但是 SharePoint 的协作功能并不适用。)相反,自定义传递扩展必须按计划的时间运行报表,并且以完全自动的方式传递它们。由于 SharePoint 能够存储文档,因此,我的传递扩展会将报表呈现为一个 PDF 文件,并将其存储在指定的文档库中。
那么,文件生成后如何存储到文档库中呢?解决方案包括一个自定义的 SharePoint Web 服务,它提供一个接口来接收报表文件,然后通过 WSS 对象模型将文件存储在适当的库中。使用自定义的 Web 服务可以增加灵活性,这样您除了存储文件还可以包括其他任务。
  为了方便在请求中包含二进制文件,Web 服务将使用带有 WS-Attachment 功能的 Web Service Enhancements (WSE) 进行直接 Internet 消息封装(Direct Internet Message Encapsulation,DIME)。我之所以选择该方法,而不选择 XML 消息中二进制数据的 base64 编码,是因为在 Unicode 字符格式中,base64 编码方法增加了请求的大小。通过 DIME 发送附件会将文件移到 SOAP 信封外。图 1 以较高级别显示该体系结构。

  该体系结构的优点在于,最终结果只是文档库中的一个文件。这样,用户就可以使用 SharePoint 必须提供的所有常规功能,包括协作和 SharePoint 警报。如果有人需要确认某个报表是有效的并在上面签字,然后其他用户才能够查看该报表,她可以打开内容审批。如果报表的内容必须是可搜索的,则只需安装一个 PDF IFilter。
返回页首
  构建 Web 服务
  自定义的 SharePoint Web 服务只有一个方法,就是 UploadDocument。该方法只接受带有一个文件附件的 SOAP Web 服务请求。为了接收来自客户端的一组参数,Web 服务公开了一个 DocInfo 类,该类是专门为提供灵活性以及版本复原而设计的。
至少,该 Web 服务必须接收两个字符串:文件名和库名。但是,解决方案必须保持灵活性,以便将来能够支持其他参数。事实上,该 Web 服务很可能为您的 SharePoint 实现增加功能,而不仅仅是存储报表。有关构建一个类以使其序列化开放的详细信息,请参见 Doug Purdy(Microsoft 的一位项目经理)在 MSDN® TV 节目中有关该主题的讨论"Loosely Coupled Web Services"。
  DocInfo 类中的元素和属性数组允许我将来添加字段,而不破坏向后兼容性。同时,版本标识符使 Web 服务方法能够发现在发出请求的客户端的级别,以便它可以作出相应的反应。
  一旦 UploadDocument Web 服务方法已经确认该请求有一个附件,它就会使用 BinaryReader 将附件读入字节数组中。在示例代码(下载代码中提供 C# 和 Visual Basic 两种版本)中,您将了解 RequestSoapContext 的使用方法。该类提供对 Web 服务的特定于 WSE 的扩展的访问。通过其 Attachments 集合,您可以访问传递扩展正发送的实际 PDF 报表文件。收到附带的报表后,UploadDocument 方法继续使用 SharePoint 对象模型进行处理,以确定客户端针对的是哪个"web": Dim site As SPWeb = SPControl.GetContextWeb(Me.Context)

  在该上下文中,"web"是一个通用的 SharePoint 对象模型术语。它可以指 Windows SharePoint Services (WSS) 站点或 SharePoint Portal Server (SPS) 区域。正确的 Web 是通过 SharePoint 上下文对象确定的,它基于客户用来发出请求的 URL。SharePoint 站点的 Web 服务以下述方式部署:可以通过任何 web 的 vti_bin 文件夹引用它们。要获得该功能,您必须确保部署 Web 服务的方式与部署现成服务的方式相同。我在本文的部署部分中详细介绍该主题。
一旦 UploadDocument 方法确定在报表应该存储在哪个 web 中,GetFolder 方法将用于检索正确的文档库。然后,库使用给定的文件名将字节数组添加到其文件集合中: Dim folder As SPFolder = site.GetFolder(info.Folder)
Dim file As SPFile = folder.Files.Add(info.FileName, fileData, True)

  该过程将报表保存到 SharePoint 文档库中。本调用中指定的 True 参数指明当前文件将覆盖任何具有相同名称的现有文件。如果用户启用了对 SharePoint 库的版本控制,则新文件实际上将更新现有的文件。如本文后面所述,传递扩展还可以选择将时间戳附加到文件名中。如果用户不希望启用库的版本控制,但还想保持全部的报表实例,这会很方便。 
  构建传递扩展
  我在前面提到的现成的传递方法(通过电子邮件传递以及将文件传递到文件共享),每种方法都包含一个传递扩展。要使报表到达 SharePoint 库,我必须构建一个自定义传递扩展。这涉及三个类的编写:一个类存储订阅设置,一个类呈现用户界面,一个类实际传递报表。当用户设置一个订阅将报表传递到 SharePoint 时,他们需要提供四部分信息:WSS 站点或 SPS 区域的 URL、文档库名、用于报表的文件名,以及是否应向文件名添加时间戳。上述每个值都存储在一个 SubscriptionData 类中。
解决方案还包括一个 SPSLibraryDeliveryUIProvider 类,它生成用于从用户捕获该信息的用户界面。该类呈现了特定于 SharePoint 库传递扩展的窗体字段。图 4 显示自定义传递扩展的订阅项窗体。SPSLibraryDeliveryUIProvider 仅负责与这些设置匹配的三个文本框和一个下拉列表。
  传递扩展的大部分工作涉及编写实际传递报表的类。我创建的类名为 SPSLibraryDeliveryProvider。它实现 IExtension 和 IDeliveryExtension 接口。当准备传递报表,并且用户已经选择了自定义解决方案作为传递方法时,Reporting Services 引擎自动实例化该类。
  在该类中,操作在 Deliver 方法中开始。该方法收到一个通知参数,该参数用于检索特定于用户的传递设置,以及与主机服务就进度或故障进行通讯。接着,Deliver 方法调用 SaveReport,这是传递扩展调用自定义 SharePoint Web 服务的位置。SaveReport 通过将报表呈现给 PDF 文件开始。
SaveReport 方法的下一部分配置 Web 引用添加到项目中时 Visual Studio® 创建的代理类。在代码中,代理类是 DocumentUtilService.DocumentUtilWse。要初始化代理,我必须将其 Url 属性设置为用户提供的 URL,但是后面需要加上 /_vti_bin/DocumentUtil.asmx。这将确保为 Web 服务方法中的代码正确地建立 SharePoint 上下文。由于 SharePoint 实际上修改了传入某个站点的 _vti_bin 目录中的请求,并将这些请求路由到虚拟服务器根目录下的 _vti_bin,因此代理必须配置一个目的终结点引用。通过设置目的终结点引用,最终的请求将传递由 WSE 中的 WS-Addressing 逻辑实施的验证。终结点引用的URL 是用 CreateVSUrl 函数构建的,它根据用户提供站点的 URL 确定虚拟服务器的 URL。
  最后,设置代理的安全凭据。Web 服务将通过分配给 ReportServer 服务的帐户的安全上下文进行调用。然而,这仅对于示例是可行的。Microsoft 不推荐以高权限运行服务,因为这样会将网络暴露给高权限的攻击。相反,您应该将特定的凭据集中在传递扩展设置中,使用这些凭据进行请求。
  SaveReport 方法的最后一部分实际上使用数据填充了请求。创建一个 DocInfo 类,并使用应该存储该类的报表的文件名及库名填充该类。此处调用的 GenerateFileName 函数采用用户指定的文件名,并添加 .pdf 文件扩展名和选定的时间戳类型(可选)。使用 RequestSoapContext.Attachments 集合将报表的二进制表示附加到请求。最后,传递扩展将其信息发送给自定义的 SharePoint Web 服务。
部署
  关键部署项在随示例代码打包的说明中进行了详细的描述,但在此处说明是为了确保您知道应该牢记它们。
  SQL Server Reporting Services 安装的 ReportServer Windows 服务应该配置有一个 Active Directory® 域帐户。通过为其分配一个域帐户,管理员能够为特定的 SharePoint 库分配传递扩展权限。
  自定义的 SharePoint Web 服务必须按照 MSDN 文章"Writing Custom Web Services for SharePoint Products and Technologies" 中描述的方式进行部署。这包括从 .wsdl 和 .disco 文件创建 .aspx 文件,并将其放在 C:\Program Files\Common Files\Microsoft Shared\Web server extensions\60\ISAPI 文件夹中。
传递扩展程序集必须部署在 SQL Server Reporting Services 的 ReportManager 和 ReportServer 目录中。传递扩展还必须添加到 RSWebApplication 和 RSReportServer 配置文件中。最后,Rssrvpolicy 和 Rsmgrpolicy 文件中还有需要解决的代码访问安全性 (CAS) 配置。有关此内容的详细信息,请参阅 MSDN 文章"Code Access Security in SQL Server 2000 Reporting Services"。
  SQL Server 2000 和SQL Server 2005
  我原先使用 SQL Server 2000 编写本文中描述的解决方案。好消息是,对于 SQL Server 2005 而言,我所依赖的接口保持不变,除了对传递扩展项目进行升级/重编译外,一切运行良好。
对于 SQL Server 2005,Reporting Services 目录位于 C:\Program Files\Microsoft SQL Server\MSSQL.3\Reporting Services 中(如果您一起安装了 SQL Server, Analysis Services 和 Reporting Services)。在将升级的 SPSLibraryDelivery.dll 放入 bin 文件夹中时,按照相同的说明修改配置文件和策略文件。
针对我的测试,我还安装了 Windows SharePoint Services Service Pack 1,扩展了一个新的 IIS Web 站点,并且创建了一个优异的小组站点。自定义 Web 服务的部署说明保持不变。

小结

  可以使用多种不同的方法来生成报表,从而为用户提供重要信息。大部分组织所面临的挑战不是生成这样的报表,而是以及时有效的方式地传递它们。通过本文所述的自定义传递扩展,可以捕获报表并将它们放在 SharePoint 文档库中,从而使用户能够以更健壮的方式(支持协作和其他有用的功能)查看和分析报表。
0
相关文章