了解 SharePoint 2010 开发中的关键设计决定

**摘要:**了解为 Microsoft SharePoint 2010 规划和开发业务解决方案时必须做出的重要设计决定。

上次修改时间: 2012年3月13日

适用范围: Business Connectivity Services | Office 2010 | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio

本文内容
SharePoint 2010 设计决定概述
作为开发平台的 SharePoint 2010
将 SharePoint 解决方案包部署为服务器场解决方案与沙盒解决方案
使用 Web 部件、网站页面或应用程序页面设计 UI
SharePoint 2010 中的服务器对象模型与客户端对象模型
访问 SharePoint 网站中基于列表的内容
在 ECMAScript 和 Silverlight 之间做出选择
结论
其他资源
关于作者

供稿人:Ted Pattison(该链接可能指向英文页面) (SharePoint MVP),Critical Path Training(该链接可能指向英文页面) | 关于作者

目录

  • SharePoint 2010 设计决定概述

  • 作为开发平台的 SharePoint 2010

  • 将 SharePoint 解决方案包部署为服务器场解决方案与沙盒解决方案

  • 使用 Web 部件、网站页面或应用程序页面设计 UI

  • SharePoint 2010 中的服务器对象模型与客户端对象模型

  • 访问 SharePoint 网站中基于列表的内容

  • 在 ECMAScript 和 Silverlight 之间做出选择

  • 结论

  • 其他资源

  • 关于作者

SharePoint 2010 设计决定概述

本文讨论为 Microsoft SharePoint 2010 设计业务解决方案的架构和开发业务解决方案时必须做出的主要设计决定。您将了解何时应该创建面向沙盒的 SharePoint 解决方案,以及何时创建仅支持服务器场级部署的 SharePoint 解决方案。本文还解释构建需要自定义用户界面 (UI) 的 SharePoint 解决方案时,如何在 Web 部件、网站页面和应用程序之间做出选择。您还将了解如何在使用服务器端对象模型和客户端对象模型之间做出决定,以及如何选择适当的技术来访问 SharePoint 列表中的内容。

作为开发平台的 SharePoint 2010

SharePoint 技术的发展历经四个主要产品版本。2001 年的第一个版本和 2003 年的第二个版本得到了顺利而适度的采用。不过,从 2007 年的第三个版本开始,SharePoint 技术得到了快速采用,真正开始迅猛发展。全球数以千计的企业、组织和政府机构已经部署了 Microsoft Office SharePoint Server 2007。SharePoint 2010 通过引入新功能和服务在 2007 版本的基础上进行了改进,这给 SharePoint 技术的继续发展带来了美好的前景。

因为经过多年的发展,SharePoint 技术的受欢迎程度已经提高,所以人们希望使用自定义 SharePoint 解决方案自定义内置体验。而且,Microsoft 继续在 SharePoint 技术上投资,力求将它转变为一流的开发平台。在 2003 版本中,Microsoft 第一次实现了使用自定义 Microsoft .NET Framework 组件(如使用 C# 或 Microsoft Visual Basic 编写的 Web 部件和事件处理程序)扩展 SharePoint 网站。在 2007 版本中,Microsoft 通过引入面向开发人员的基本构建基块(如内容类型、网站栏、功能和解决方案包)将 SharePoint 更新为开发平台。

尽管 SharePoint 2010 的许多新方面改进了 SharePoint 开发人员平台,但是事实证明最重要的一个方面是称为 Microsoft Visual Studio 2010 中的 SharePoint 开发工具的新工具集。Visual Studio 2010 中的 SharePoint 开发工具是一个很大的进步,因为它们隐藏并自动完成 SharePoint 开发的许多繁琐的方面,例如从 SharePoint 项目中的源文件生成解决方案包。通过 Visual Studio 2010 中的 SharePoint 开发工具,还可以方便地将 SharePoint 项目的解决方案包部署到本地服务器场,以便您可以在开发工作站上测试和调试代码。

Visual Studio 2010 中的 SharePoint 开发工具非常适合初学者和刚刚开始 SharePoint 开发的 .NET 开发人员,因为它使他们可以快速地熟练掌握新技术和提高工作效率。Visual Studio 2010 中的 SharePoint 开发工具还设计为具有可扩展性,这使有经验的 SharePoint 开发人员可以使用工具集本身不直接支持的高级开发技术。

除了 Visual Studio 2010 中新的支持,SharePoint 2010 开发平台还引入了一些其他改进。例如,SharePoint 2010 允许您将解决方案包部署为服务器场解决方案或部署为沙盒解决方案。SharePoint 2010 引入了新客户端对象模型,以补充自 2003 版本以来已成为 SharePoint 开发平台一部分的服务器端对象模型。SharePoint 2010 还引入了访问 SharePoint 列表中的内容的新选项,包括 LINQ(语言集成查询)支持和基于 REST 的 Web 服务。

具有不同的选项固然很好,但您任何时候都不可能使用所有这些选项。事实上,每次开始为特定应用场景设计新 SharePoint 解决方案时,您都必须在这些选项之间做出选择。下面各节介绍要考虑的关系最密切的设计问题,以便您可以在设计和开发新 SharePoint 解决方案时作出最佳选择。

将 SharePoint 解决方案包部署为服务器场解决方案与沙盒解决方案

SharePoint 开发中的一个基本概念是解决方案包。在物理级别,解决方案包是一个 CAB 存档,它包含在 SharePoint 环境中部署自定义开发成果所需的文件和元数据。从设计的角度来看,解决方案包是用于重用、测试和部署的基本单位。解决方案包还提供可用于将更新推送到 SharePoint 场以修复错误并扩展已部署的解决方案的粒度。

在 SharePoint 2010 中可以通过两种方式部署解决方案包:部署为服务器场解决方案或部署为沙盒解决方案。每次使用 Visual Studio 2010 中的 SharePoint 开发工具创建新 SharePoint 项目时,都会强制您选择将代码作为沙盒解决方案还是作为服务器场解决方案进行开发和测试。您的决定应该基于是要开发和测试 SharePoint 解决方案以仅支持服务器场级部署,还是要将它作为可以灵活地部署为服务器场解决方案或沙盒解决方案的 SharePoint 解决方案进行测试。

部署为服务器场解决方案的解决方案包必须由服务器场管理员部署。因为服务器场解决方案部署需要将自定义文件复制到服务器场中的每个 Web 服务器上,所以会对服务器场的运行状况带来一定风险。此外,大多数服务器场解决方案在 Web 服务器上的全局程序集缓存中安装自定义程序集 DLL,这允许内部的代码在完全信任级别运行。因此,许多服务器场管理员要求对 SharePoint 解决方案进行冗长的代码检查和严格的测试过程,然后再将其部署到生产场。有些 SharePoint 环境中的服务器场管理员要求更甚,完全禁止 SharePoint 解决方案的服务器场级部署。

SharePoint 2010 引入了新的沙盒体系结构,能提供有价值的服务器场级部署替代方法。与服务器场解决方案部署不同,沙盒解决方案部署不需要服务器场管理员的批准或协助。相反,作为沙盒解决方案开发的 SharePoint 解决方案可以由网站集所有者或网站管理员角色中的业务用户上载和激活。这样可大大加快自定义 SharePoint 解决方案投入使用的过程。通过沙盒解决方案还可以开发面向不允许服务器场解决方案部署的环境(如 SharePoint Online)的自定义解决方案。

关于新沙盒体系结构,有一点非常重要但却常被误解。将 SharePoint 解决方案作为沙盒解决方案设计和开发并不意味着必须始终将它部署为沙盒解决方案。相反,您可以将面向沙盒开发的 SharePoint 解决方案部署为沙盒解决方案或部署为服务器场解决方案。这意味着将 SharePoint 解决方案作为沙盒解决方案开发可以在各种部署方案中提供更大的灵活性。

我们来看一个沙盒解决方案如何提供这种灵活性的示例。在不允许服务器场级解决方案部署的 SharePoint 场中,具有网站管理员权限的用户可在网站集上下文内上载和激活 SharePoint 解决方案。在另一个没有这些限制的 SharePoint 场中,相同的 SharePoint 解决方案可部署为服务器场解决方案,这样就能获得更高级别的性能和可维护性。这样,当沙盒的约束不会阻止您完成所需操作时,您就会有面向沙盒的设计动机。

沙盒解决方案的限制

决定是否应该将 SharePoint 解决方案作为沙盒解决方案开发时,关键是了解沙盒中允许的操作和禁止的操作。例如,不允许沙盒解决方案将文件部署到 Web 服务器的文件系统。这意味着沙盒解决方案不能包含以下任一内容:

  • 安装在全局程序集缓存中的程序集

  • 在服务器场级别激活的功能

  • 在 Web 应用程序级别激活的功能

  • 应用程序页面

  • 用户控件

  • 可视 Web 部件

  • 顺序工作流模板

  • 状态机工作流模板

  • Business Data Connectivity (BDC) Service 模型

在可以使用服务器端代码执行的操作方面也有重要限制。尽管沙盒解决方案可以包含使用服务器端对象模型的代码,但服务器端对象模型的许多部分仍被禁止使用。例如,沙盒解决方案中的代码不能访问服务器端对象模型中当前网站集范围之外的任何内容。不能使用 SPSite 类创建新对象以访问其他网站集。此外,不允许访问服务器端对象模型的服务器场级别的任何方面,如 SPFarm 对象或 SPWebApplication 对象。

以下列表显示只有在服务器场解决方案中部署代码时才能完成的常见编程任务:

  • 创建和配置 Web 应用程序

  • 创建和配置内容数据库

  • 创建网站集

  • 聚合存储在两个或更多网站集中的内容

除了服务器端对象模型的编程限制,沙盒体系结构还进一步限制您使用 Microsoft .NET Framework 提供的许多类库。SharePoint Foundation 通过在使用代码访问安全性 (CAS) 设置初始化的独立工作进程中运行沙盒代码来强制实施这些限制。例如,不能访问 System.IO 命名空间中的任何类。此外,沙盒解决方案中的服务器端代码不能访问允许您通过网络访问资源的任何 .NET Framework 部分。这意味着您无法连接到数据库、进行出站 Web 服务调用,甚至无法发出简单的 HTTP GET 请求。

显而易见,沙盒对您可以在服务器端代码中执行的操作设置了重要限制。代码可以访问内容的唯一位置是在上载并激活沙盒解决方案的网站集中。这些限制可能会强制您在开发需要通过网络访问资源(如 Web 服务和数据库)的 SharePoint 项目时重新考虑您的设计。

在需要访问网络资源的方案中,可能应该选择服务器场解决方案而不是沙盒解决方案。不过,可以考虑另外一个选项。尽管沙盒解决方案体系结构限制服务器端代码可以执行的操作,但是它不对客户端代码施加任何限制。因此,您可以使用在可以访问网络资源的 ECMAScript(JavaScript、JScript)或 Microsoft Silverlight 应用程序中编写的客户端代码来设计沙盒解决方案。在本文中我们将继续讨论该设计选项。

备注

Microsoft 使用术语 JavaScript 而不是 JavaScript。有关详细信息,请参阅下文中的 SharePoint 客户端对象模型如何工作?一节。

沙盒解决方案的常见开发应用场景

对许多类型的 SharePoint 项目来说,对沙盒解决方案设置的限制通常过于严格。不过,有一些简单业务解决方案类别完全可以使用沙盒解决方案实现。下面是使用沙盒解决方案可以满足的要求列表:

  • 创建自定义网站栏、内容类型和列表定义

  • 创建列表并添加用于数据验证的事件处理程序

  • 在"快速启动"菜单和顶部导航栏上创建导航节点

  • 添加查询和更新列表的 Web 部件

  • 添加网站页面以托管 Web 部件和 Silverlight 应用程序

  • 使用自定义母版页、CSS 文件和图像确立 SharePoint 网站的品牌

使用 Web 部件、网站页面或应用程序页面设计 UI

在 SharePoint 项目中设计 UI 时要考虑一些重要设计问题。例如,是否应该使用 Web 部件、网站页面模板或应用程序页面创建 UI 元素?在用于创建自定义 UI 元素的这三种技术中,每种技术在特定应用场景中都具有胜于其他两种技术的优势。不过,您可能会发现每种方法非常适用的其他方案,这意味着决定使用哪种方法完全取决于开发人员的个人喜好。

认真思考手头的设计方案,并问自己以下问题:

  • 是否需要支持用户自定义和个性化?

  • 是否担心赋予用户的控制权太多?

  • UI 是否需要用 C# 或 Visual Basic 编写的服务器端代码?

  • 是否需要使用沙盒解决方案部署 UI?

支持网页的用户自定义

首先讨论第一个问题 — 是否需要支持用户自定义和个性化。如果是,则最佳选择是使用 Web 部件构建 UI。这是因为 SharePoint Foundation 使用户能够添加、自定义、个性化和删除 Web 部件。许多曾经使用过 SharePoint 技术的用户非常擅于向页面添加 Web 部件,并通过浏览器中的任务窗格自定义它们。

网站页面也提供某种程度的用户自定义支持,但是不如 Web 部件简单。例如,用户不能使用浏览器自定义网站页面的基础内容,而是必须依赖于与 SharePoint 兼容的页面编辑工具,如 Microsoft SharePoint Designer 2010。不过,您应该知道,使用 SharePoint Designer 2010 修改网站页面需要理解复杂的主题,如 HTML 编辑、服务器端控件和母版页。因此,网站页面自定义应该仅限于涉及的高级用户可以熟练使用 SharePoint Designer 2010 设计 SharePoint 页面的应用场景。

如果您决定使用 Web 部件构建 UI,则应该考虑如何将这些 Web 部件添加到 SharePoint 网站中的页面。最简单的方法只涉及创建 Web 部件,而不涉及任何其他操作。这是用户需要向现有 Web 部件页面添加 Web 部件实例的相当常见的应用场景。更完善的方法涉及在功能激活期间自动完成向网站页面添加 Web 部件的工作。

在 SharePoint 解决方案中创建 Web 部件时,应考虑是否需要另外创建页面以托管 Web 部件。如果您认为应该这样做,则不能使用应用程序页面,因为它们不支持 Web 部件。而是必须设计一个或多个满足 Web 部件页面要求的网站页面模板。创建网站页面模板后,可以将它添加到 SharePoint 解决方案的模块中,以便在功能激活期间创建新网站页面实例。最后一步是使用 Web 部件实例预先填充网站页面。为此,您可以在 File 元素内部添加 AllUserWebPart 元素,这将在功能激活期间创建网站页面。

控制 UI 自定义

现在,我们来考虑第二个问题。您是否担心赋予用户的网站控制权太多?许多开发人员害怕喜欢尝试并且常常惹麻烦的粗心大意的用户。例如,假定您的 UI 设计涉及具有 Web 部件的网站页面。有什么方法可以防止特权用户和被误导的用户将页面置于编辑模式然后删除 Web 部件?您可以想象这可能导致拨打支持电话,并且 SharePoint 网站在一段时间内不可用,直到具有更多专业技能的人员介入,将适当的 Web 部件重新添加到页面。

应用程序页面不支持任何形式的用户自定义。因此,在希望锁定 UI 的设计中使用它们可能非常有利。尝试锁定使用网站页面和 Web 部件构建的 UI 可能很繁琐,在用户具有网站所有者权限的应用场景中通常不可行。

在 UI 后台使用服务器端代码

要考虑的下一问题是是否要在 UI 后台编写服务器端代码。如果要,则必须选择 Web 部件或应用程序页面。更具体地说,应该避免在网站页面和网站页面模板中编写服务器端代码。这是因为网站页面必须支持安全模式处理,这会阻止用 C# 或 Visual Basic 编写的内嵌代码。尽管从技术上讲可以使用 C# 或 Visual Basic 创建自定义基类并在网站页面模板中从此基类继承,但是不建议使用这种方法。它可能非常麻烦,很少用于 SharePoint 开发,因为向 Web 部件或在应用程序页面后台添加服务器端代码容易得多。

将 UI 部署为沙盒解决方案

设计自定义 UI 时要考虑的另一重要问题是是否需要支持部署为沙盒解决方案。如果是,则必须避免使用不能由沙盒解决方案正确部署的应用程序页面。这意味着必须使用网站页面和 Web 部件构建 UI。

SharePoint 2010 中的服务器对象模型与客户端对象模型

从 2003 版本开始,SharePoint 向开发人员提供了服务器端对象模型,以访问网站中的内容和在网站级别执行各种管理任务,如创建列表、添加导航节点和配置权限。通过服务器端对象模型还可以在服务器场级别执行管理任务,如创建和配置 Web 应用程序及内容数据库。

服务器端对象模型通过名为 Microsoft.SharePoint.dll 的程序集提供,该程序集部署在 SharePoint 场中的每个服务器上。这意味着开发在 Web 服务器上运行的 SharePoint 组件(如功能接收器、事件处理程序、Web 部件、应用程序页面和工作流模板)时,可以使用服务器端对象模型。不过,服务器端对象模型不能直接用于在不属于 SharePoint 场的计算机上运行的应用程序和组件。

SharePoint 2010 引入了新客户端对象模型,它允许通过网络访问 SharePoint 网站。例如,您可以使用客户端对象模型在可以通过网络连接到 SharePoint 网站的桌面应用程序中编写代码。使用客户端对象模型连接到 SharePoint 网站后,您可以读取和更新列表和文档库中的内容。还可以在网站中执行管理任务,如创建新列表、添加导航节点和配置用户权限。

客户端对象模型可以有效地用于多种类型的应用程序。例如,通过客户端对象模型,您可以使用 Windows Forms 和 Windows Presentation Foundation (WPF) 开发在 SharePoint 网站中读取和写入内容的桌面应用程序。客户端对象模型还非常适用于编写在浏览器中的页面后台运行的客户端代码,如自定义 JavaScript 代码或 Silverlight 应用程序。

使用客户端对象模型的主要好处是它可以显著改进用户体验。这是因为您可以编写在用户计算机上执行的代码,这样不再需要回发和混乱的页面切换。例如,可以在命令按钮后台编写客户端代码,以更新 SharePoint 网站中的列表项,然后刷新 UI 以反映此更改。重要的是,在执行这项工作时,不会强制用户忍受页面切换或回发。

SharePoint 客户端对象模型如何工作?

SharePoint 2010 中的客户端对象模型基于 Windows Communication Foundation (WCF) 构建,WCF 用于在客户端计算机和 Web 服务器之间建立通信。SharePoint Foundation 使用名为 Client.svc 的 WCF Web 服务文件在服务器场中的每个 Web 服务器上提供一个客户端对象模型的入口点。

请注意,无需理解 WCF 的工作原理即可使用客户端对象模型。实际上,客户端对象模型专门设计用于对 SharePoint 开发人员隐藏 WCF 管道的基础详细信息。使用客户端对象模型时,您只需创建对象并访问它们的方法和属性。客户端对象模型提供客户端运行库,该运行库使用 WCF Web 服务调用处理与 Web 服务器的通信。

可以从三种类型的客户端应用程序访问客户端对象模型,它们是 .NET Framework 应用程序、Silverlight 应用程序和在 SharePoint 网站中的页面上运行的 JavaScript 代码。如果要开发 .NET Framework 应用程序,则可以通过引用以下程序集访问客户端对象模型:

  • Microsoft.SharePoint.Client.dll

  • Microsoft.SharePoint.Client.Runtime.dll

请注意,除使用客户端对象模型的任何 .NET Framework 应用程序外,还必须部署这两个程序集。如果在运行时不能加载这两个程序集,则使用客户端对象模型编写的 .NET Framework 应用程序将无法正确运行。

如果要开发 Silverlight 应用程序,则可以通过引用以下程序集访问客户端对象模型:

  • Microsoft.SharePoint.Client.Silverlight.dll

  • Microsoft.SharePoint.Client.Silverlight.Runtime.dll

请注意,每次 Silverlight 应用程序开始使用客户端对象模型时,这两个程序集都必须可加载到浏览器的进程中。不过,部署这两个程序集的步骤由 Visual Studio 2010 自动处理。创建新 Silverlight 项目并添加对这两个程序集的引用时,Visual Studio 2010 会配置项目的生成过程以自动将这两个程序集嵌入用于部署 Silverlight 应用程序的 .xap 文件中。这使您能够随依赖这些程序集的任何 Silverlight 应用程序部署这些程序集。

现在该讨论从自定义 ECMAScript(JavaScript、JScript)代码使用客户端对象模型了。首先要了解的是 Microsoft 使用术语 JavaScript 而不是 JavaScript。例如,本文提到 JavaScript 客户端对象模型。不要因为术语 JavaScript 而感到困惑。它是可以与 JavaScript 互换使用的术语。

如果在 SharePoint 网站中的页面上编写客户端 JavaScript 代码,则可以通过名为 sp.js 的标准库文件访问 JavaScript 客户端对象模型,该文件部署在服务器场中的每个 Web 服务器上。在开始使用 JavaScript 客户端对象模型之前,必须确保 sp.js 已下载并且可供页面使用。为此,您可以在 JavaScript 中调用 ExecuteOrDelayUntilScriptLoaded 方法并传递自定义函数名称和 sp.js 的文件名。

ExecuteOrDelayUntilScriptLoaded(MyEcmaScriptCode, "sp.js");

function MyEcmaScriptCode() {

  // This code will not execute until sp.js is fully downloaded.
}

备注

SharePoint 中的许多标准 JavaScript 库文件(如 sp.js)都配置为在页面已显示给用户之后按需加载。这种新的延迟加载技术是在 SharePoint 2010 中引入的,以提供响应速度更快的 UI 体验。不过,开发人员对延迟加载还存在顾虑。问题在于,如果在文件尚未下载到浏览器时尝试访问 sp.js 中的任何内容,则会遇到运行时错误。

对 ExecuteOrDelayUntilScriptLoaded 的调用强制托管页面在尝试执行自定义函数之前完全下载 sp.js。这是可用于确保客户端 JavaScript 代码可以成功调用 sp.js 并开始使用客户端对象模型的一种技术的示例。

异步执行客户端对象模型方法

开始使用客户端对象模型时,您通常会发现不能使用同步行为对 Web 服务器执行方法。这是因为同步调用会占用主要 UI 线程,并导致冻结 UI,直到方法调用返回。在应用程序设计中,通过网络进行调用时冻结 UI 通常无法让人接受。因此,必须了解如何异步对 Web 服务器执行方法。

例如,开发使用客户端对象模型的 Silverlight 应用程序时,应该始终使用 ExecuteQueryAsync 方法异步调用 Web 服务器。调用 ExecuteQueryAsync 方法时,必须将委托引用传递给回调方法。这些回调方法在调用从 Web 服务器返回时执行。以下代码示例演示编写为与 Web 服务器异步交互的简单 Silverlight 应用程序。

public partial class MainPage : UserControl {
  protected ClientContext clientContext;
  protected Web site;

  public MainPage() {
    InitializeComponent();
    clientContext = new ClientContext("http://intranet.wingtip.com");
    site = clientContext.Web;
    clientContext.Load(site);
    clientContext.ExecuteQueryAsync(OnSucceed, OnFail);
  }

  void OnSucceed(object sender, ClientRequestEventArgs args) {

    // Callback method that executes when there are no errors.
  }

  void OnFail(object sender, ClientRequestEventArgs args) {

    // Callback method that executes when there are errors.
  }
}

开发人员面临的另一难题涉及在回调方法中编写用于处理线程切换的代码。使用客户端对象模型时需要这样做,因为回调方法在辅助线程上执行,而辅助线程不能访问 UI 中的控件,如文本框和数据网格。关键点在于开发人员负责将执行流从辅助线程切换回主 UI 线程。执行流切换到主 UI 线程后,可以更新控件。下面的示例演示如何使用 Silverlight 应用程序中的 Dispatcher.BeginInvoke 方法进行线程切换以更新文本框控件。

void OnSucceed(object sender, ClientRequestEventArgs args) {

  // Running on secondary thread.
  Dispatcher.BeginInvoke(delegate() {

    // Running on primary UI thread.
    txtDisplay.Text = "Site ID = " + site.Id.ToString();
  });
}

从这些示例中您可能会发现,使用客户端对象模型需要高级编程技能。因此,使用客户端对象模型开发可能更适合高级开发人员,而不是初学者。

访问 SharePoint 网站中基于列表的内容

SharePoint 2010 提供了用于访问 SharePoint 网站中基于列表的内容的多种不同选项。您可以在服务器端代码中使用 SPQuery 对象或 SPSiteDataQuery 对象访问列表中的项。还可以决定使用新 LINQ to SharePoint 支持编写查询和更新列表项的服务器端代码。说到编写客户端代码,客户端对象模型和基于 REST 的新 Web 服务提供了另外两个选项。本节介绍上述每种技术,并讨论它们的相对优点和缺点。

在 2003 版本中,Microsoft 在服务器端对象模型中引入了 SPQuery 类,以提供一种查询 SharePoint 列表中的项的途径。使用 SPQuery 类要求开发人员集中分析 XML 片段,以便采用称为协作应用程序标记语言 (CAML) 的语言参数化查询。下面是一个典型示例,演示使用 SPQuery 对象对 SharePoint 列表执行查询需要执行的操作。

SPList contacts = this.Web.Lists["Contacts"];
SPQuery query = new SPQuery();
query.ViewFields = "<FieldRef Name='Title'/>" + 
                    "<FieldRef Name='FirstName'/>" +
                    "<FieldRef Name='Email'/>" +
query.Query = @"<Where>
                  <BeginsWith>
                    <FieldRef Name='FirstName'/>
                    <Value Type='Text'>B</Value>
                  </BeginsWith>
                </Where>
                <OrderBy>
                  <FieldRef Name='Title'/>
                  <FieldRef Name='FirstName'/>                        
                </OrderBy>";

SPListItemCollection results = contacts.GetItems(query);
foreach (SPListItem item in results) {

  // Enumerate through items.
  string FirstName = item["FirstName"].ToString()
}

SPQuery 类非常有用,因为它提供在编写服务器端代码时对大型列表运行查询的有效方式。使用 SPQuery 对象的主要不利因素与开发人员工作效率相关。Visual Studio 2010 在集中分析所需 CAML 片段方面不提供任何帮助。这通常导致开发人员通过频繁复制并粘贴工作示例中的 CAML 片段来重用技术,这样做效率很低。不过,还存在以下问题:对列值的访问未强类型化,而是必须通过以字符串形式传递列名称来读取和写入列值。

string s = item["Title"].ToString()

缺少用于访问列表中的列值的强类型化技术产生了一些值得注意的不利因素。C# 编译器和 Visual Basic 编译器无法确定列名称拼写错误的情况。编译器还无法确定开发人员是否已正确将列值转换为正确的类型。这会导致只有在测试阶段才能发现的错误。缺少强类型化的列访问还导致在选择要访问的列时 Visual Studio 2010 无法通过 IntelliSense 提供任何帮助。

在 2007 版本中,Microsoft 添加了 SPSiteDataQuery 类以补充 SPQuery 类。SPSiteDataQuery 类允许开发人员执行将多个列表中的项聚合到单个结果集中的查询。例如,假定您要运行单个查询,该查询可以查找并聚合当前网站集中所有联系人列表中的联系人。您可以使用 SPSiteDataQuery 对象来运行以下查询,该对象将查询范围设置为当前网站集并提供基于 Contact 内容类型的 where 子句。

SPSiteDataQuery query = new SPSiteDataQuery();
query.Webs = "<Webs Scope='SiteCollection' />";
query.ViewFields = "<FieldRef Name='Title'/>" + 
                   "<FieldRef Name='FirstName'/>" +
                   "<FieldRef Name='Email'/>";
query.Query = @"<Where>
                  <FieldRef Name='ContentType'/>
                  <Value Type='Computed'>Contact</Value>
                </Where>";
DataTable results = this.Web.GetSiteData(query);
foreach (DataRow item in results.Rows) {

  // Enumerate through items.
  string FirstName = item["FirstName"].ToString()
}

能够运行聚合多个列表中的项的查询毫无疑问使 SPSiteDataQuery 具备了优于其他列表访问技术的独特功能。因此,在需要聚合的应用场景中,它对 SharePoint 开发人员非常有用。不过,SPSiteDataQuery 类与 SPQuery 类一样,都会对开发人员的工作效率产生不利影响,因为它强制开发人员集中分析 CAML 片段,并且它不提供对列值的强类型化访问。

SPSiteDataQuery 类的另一个潜在问题是它可能导致效率很低的查询,这类查询花费很长时间运行并且消耗 Web 服务器的大量处理周期。因此,在使用 SPSiteDataQuery 类时,应确保充分执行性能测试。还应该考虑避免在访问频率较高的页面(如网站的主页)的后台使用 SPSiteDataQuery 类。

使用 LINQ to SharePoint 提供程序支持

Microsoft 在 SharePoint 2010 中引入了一项支持,该支持允许服务器端代码使用 LINQ(语言集成查询)针对 SharePoint 列表执行查询。该支持由作为 SharePoint Foundation 中的标准组件安装的 LINQ to SharePoint 提供程序实现。

使用 LINQ to SharePoint 提供程序访问 SharePoint 列表中的项的主要优势是提高了开发人员的工作效率。使用 LINQ 访问 SharePoint 列表时,无需使用 CAML。相反,您可以直接使用 C# 或 Visual Basic 编写 where 子句和 order by 子句。

通过使用 LINQ,还能够以强类型化的方式针对列值进行编程。这允许编译器在开发人员出现列名称或列类型错误时生成错误。LINQ 的强类型化特性还使 Visual Studio 2010 可以向 IntelliSense 提供一个下拉列表,以列表形式显示所有可用列。

检查编写为针对 SharePoint 列表执行 LINQ 查询的以下代码,并将它与前面所示的使用 CAML 的示例进行比较。

WingtipSiteDataContext dc = new WingtipSiteDataContext(this.Web.Url);
var query = from contact in dc.Contacts
            where contact.FirstName.StartsWith("B")
            orderby contact.LastName
            select contact;
foreach (var item in query) {

  // Enumerate through items.
  string FirstName = item.FirstName;
}

LINQ to SharePoint 提供程序还可以在向 SharePoint 列表添加新项时提高开发人员的工作效率。与查询列表项时一样,LINQ to SharePoint 提供程序在您向新列表项分配列值时启用强类型化和 IntelliSense。下面是使用 LINQ 支持添加新列表项的一个示例。

WingtipSiteDataContext dc = new WingtipSiteDataContext(this.Web.Url);
Contact newContact =
  new Contact {
    FirstName = "Wendy",
    LastName = "Wheeler"
    EMail = "wendy@wheeler.com"
  };
dc.Contacts.InsertOnSubmit(newContact);
dc.SubmitChanges();

显而易见,LINQ to SharePoint 提供程序向需要查询和更新 SharePoint 列表项的开发人员提供了明确的好处。不过,您应该了解 LINQ to SharePoint 提供程序实际上只表示 CAML 上的生产效率层。在后台,LINQ to SharePoint 提供程序将 LINQ 查询语句转换为 CAML 然后使用 CAML 对内容数据库执行这些查询。因此,结合使用 CAML 和 SPQuery 类或 SPSiteDataQuery 类无法完成的操作实际上使用 LINQ to SharePoint 提供程序也无法完成。不过,反过来说则不尽然。使用 LINQ 无法完成的一些操作可以使用 SPQuery 类和 SPSiteDataQuery 类来完成。

使用 LINQ to SharePoint 提供程序的一个问题是您必须提前了解列的情况。在编写使用 LINQ to SharePoint 提供程序的代码之前,必须首先运行 spmetal.exe 实用工具以生成 LINQ 编程中所需的实体类。这导致在代码必须在运行时发现列表中的列名称和类型的应用场景中,无法使用 LINQ。

另一个问题是 LINQ to SharePoint 提供程序不支持与 SPSiteDataQuery 类及其功能(运行将网站集中多个列表中的项聚合在一起的查询)相匹配的任何行为。相反,必须使用 LINQ to SharePoint 提供程序运行多个查询,然后编写您自己的代码将结果聚合在单个结果集中。

有关 LINQ to SharePoint 提供程序的最后一点说明是目前它不提供禁用限制的方法。这意味着使用 LINQ to SharePoint 提供程序执行的查询面临以下风险:返回的项数超过当前 Web 应用程序的限制阈值时失败。使用 SPQuery 类或 SPSiteDataQuery 类执行查询时无限制,因为您可以通过将 QueryThrottleMode 属性设置为值 Override 来禁用限制。

SPQuery query = new SPQuery();
query.QueryThrottleMode = SPQueryThrottleOption.Override;

现在我们已经介绍了用于通过服务器端代码访问 SharePoint 列表的技术。不过,某些 SharePoint 设计方案更适合使用客户端代码而不是服务器端代码。因此,您还应该了解用于通过网络查询 SharePoint 列表项的选项有哪些。一个选项是使用客户端对象模型访问 SharePoint 列表。另一选项是使用 SharePoint Foundation 附带的基于 REST 的新 Web 服务。下一节将分析这两种技术,以便将它们与您刚刚了解的服务器端技术相比较。

使用 SharePoint 客户端对象模型访问列表项

客户端对象模型为可以在网站集中完成的操作提供了各种功能。例如,您可以使用客户端对象模型编写用于添加用户、创建列表和配置权限的代码。除了这种类型的功能,客户端对象模型还提供读取和写入列表项的功能。

对查询列表项的客户端对象模型支持通过 CamlQuery 类实现。顾名思义,使用 CamlQuery 运行查询需要您依照 CAML 工作,如以下示例所示。

clientContext = new ClientContext("http://intranet.wingtip.com");
site = clientContext.Web;
clientContext.Load(site);
List contactsList = site.Lists.GetByTitle("Contacts");
clientContext.Load(contactsList);
CamlQuery query = new CamlQuery();
query.ViewXml = @"<View>
                    <Query>
                      <FieldRef Name='Title' />
                      <FieldRef Name='FirstName'/>
                      <FieldRef Name='Email'/>
                      <Where>
                        <BeginsWith>
                          <FieldRef Name='FirstName'/>
                          <Value Type='Text'>B</Value>
                        </BeginsWith>
                      </Where>
                    </Query>
                  </View>";
ListItemCollection contactsCollection;
contactsCollection = contactsList.GetItems(customersQuery);
clientContext.Load(contactsCollection);
clientContext.ExecuteQueryAsync(OnSucceed, OnFail);

使用客户端对象模型查询和更新列表项具有与使用 SPQuery 类和 SPSiteDataQuery 类相同的一些不利因素。即,您需要集中分析 CAML 片段。这意味着编译器无法捕获 CAML 片段中的任何错误。此外,编写查询时不能获得任何 IntelliSense 帮助。

使用基于 REST 的 Web 服务访问 SharePoint 列表项

用于查询和更新列表项的最后一种技术涉及使用 SharePoint Foundation 中内置的基于 REST 的新 Web 服务。基于 REST 的这一 Web 服务使用名为 ListData.svc 的 WCF Web 服务文件公开,该文件可通过 _vti_bin 目录访问。通过 ListData.svc,可以基于在末尾包含列表标题的相对于网站的 URL,使用简单的 HTTP GET 请求访问 SharePoint 列表中的项,如以下示例所示。

http://intranet.wingtip.com/\_vti\_bin/ListData.svc/Contacts

使用基于 REST 的 Web 服务的一个好处是它可以从几乎任意类型的客户端(包括浏览器)访问。另一相关好处是任何命令都可以通过追加查询字符串参数化为目标 URL。创建 URL 以通过 ListData.svc 访问列表项时,可以添加 QueryString 参数以选择字段并控制筛选和排序,如以下示例所示。

ListData.svc/Contacts()?$select=FirstName,LastName

ListData.svc/Contacts()?$filter=startswith(FirstName, 'B')

ListData.svc/Contacts()?$orderby=FirstName

使用 ListData.svc 的另一重要好处是它会生成符合新出现的 Web 协议(如 Atom 发布协议 (AtomPub) 和开放式数据协议 (OData))的 XML 响应。将 OData 标准化为客户端和 Web 服务之间的协议在 Microsoft 内和整个行业中越来越常用。它的普遍应用是因为它能够提供一种简单的标准化方式来公开和访问各种数据源(如关系数据库、文件系统、标准网站以及现在的 SharePoint 列表)中的内容。

SharePoint 团队使用 WCF Data Services 实现基于 REST 的 Web 服务,这一点也非常重要。SharePoint 与 WCF Data Services 的集成带来了新的好处,因为它使您能够使用 LINQ 查询语句检索 SharePoint 列表项。此外,它还允许您使用强类型化属性访问列值。这会产生类似于使用 LINQ to SharePoint 提供程序的开发人员体验,因为编译器和 IntelliSense 在您编写查询时可提供额外的帮助。

若要在 Visual Studio 2010 项目中创建服务引用,您必须传递指向 ListData.svc 的相对于网站的 URL。当 Visual Studio 2010 从 ListData.svc 创建服务引用时,它会生成包含网站的数据上下文类和每个列表的 LINQ 兼容实体类的代码。数据上下文类基于 DataServiceQuery 类为每个列表公开一个属性,这样您就可以使用 LINQ 查询语句执行远程查询,如以下示例所示。

String url = "http://intranet.wingtip.com/_vti_bin/ListData.svc";
WingtipSiteDataContext dc = new WingtipSiteDataContext(new Uri(url));
var query = from contact in dc.Contacts
            where contact.FirstName.StartsWith("B")
            select contact;
foreach (var item in query) {

  // Strongly typed access to column value.
  string FirstName = item.FirstName;
}

如果计划从 JavaScript 代码或在浏览器中运行的 Silverlight 应用程序调用 ListDava.svc,则还必须了解如何异步执行查询。下面是 Silverlight 应用程序的一个示例,该应用程序使用针对 ListDava.svc 创建的服务引用异步执行远程查询。

public partial class MainPage : UserControl {
  String url = "http://intranet.wingtip.com/_vti_bin/ListData.svc";
  protected WingtipSiteDataContext dataContext;
  protected DataServiceQuery<ContactsItem> ContactsQuery;

  public MainPage() {
    InitializeComponent();
    dataContext = new WingtipSiteDataContext(new Uri(url)); 
    ContactsQuery = 
         (from contact in dataContext.Contacts
          where contact.FirstName.StartsWith("B")
          select contact) as DataServiceQuery<ContactsItem>;
    ContactsQuery.BeginExecute(DisplayContacts, null);
  }

  public void DisplayContacts(IAsyncResult result) {
    Dispatcher.BeginInvoke(delegate(){
      var queryResults = ContactsQuery.EndExecute(result);
      foreach (var contact in queryResults) {

        // Access columns using strongly typed properties.
        string FirstName = customer.FirstName;
      }       
    });
  }
}

请注意,以下示例实现了 DisplayContacts 回调方法,以使用前面讨论的 Dispatcher.BeginInvoke 方法执行线程切换。针对 ListData.svc 异步执行查询类似于使用客户端对象模型,因为您必须在更新 UI 中的任何控件之前将回调方法的执行切换回主线程。

在 ECMAScript 和 Silverlight 之间做出选择

在现代 Web 应用程序设计中,添加客户端代码的要求越来越普遍。毕竟,具有丰富客户端行为的网站现在已经成为 Internet 上的标准。向 SharePoint 解决方案添加客户端代码无疑是改进用户体验的一种方法。

除了改进用户体验之外,在一些 SharePoint 设计方案中,客户端代码还可以执行服务器端代码无法执行的操作。我们来分析一个简单的示例。假定您需要开发一个沙盒解决方案,以便从 Internet 上的公共 Web 服务检索内容,然后将这些内容写入 SharePoint 列表。在沙盒解决方案中使用服务器端代码存在的问题是无法调用 Web 服务。

不过,您可以重新设计沙盒解决方案以包含直接从用户浏览器调用 Web 服务的自定义 JavaScript 代码或 Silverlight 应用程序。客户端代码从 Web 服务检索内容后,即可使用客户端对象模型或 ListData.svc 将这些内容写入 SharePoint 列表。本例还提供了为什么可能要在 SharePoint 解决方案中包含客户端代码的另一动机。

如果您决定向 SharePoint 解决方案添加客户端代码,则下一步是选择在页面后台编写自定义 JavaScript 代码,或者开发一个或多个 Silverlight 应用程序。我们来看一下每种方法的利弊。

JavaScript 具有适用范围大于 Silverlight 的优势,因为它在更多浏览器中受支持。此外,浏览器包含对 JavaScript 的内置支持,而在用户下载并安装 Silverlight 运行库之前 Silverlight 应用程序无法运行。尽管下载并安装 Silverlight 运行库可以通过 Internet 在几秒钟内完成,您仍然必须承认,Silverlight 开发假定用户将信任 Microsoft 软件组件并通过 Internet 进行安装。在覆盖范围很广的方案中做出这种假设可能不合适,例如在开发面向 Internet 的商用应用程序时,此时您希望覆盖最大数量的潜在用户。

在大多数 SharePoint 2010 环境中,通常可以假定随 SharePoint 解决方案部署 Silverlight 应用程序不会导致问题。毕竟,SharePoint Foundation 在标准页面(例如,通过选择"网站操作"菜单上的"其他选项"命令获得的创建页面)中包含一些不同的 Silverlight 3 应用程序。

SharePoint 2010 用户需要安装 Silverlight 3 才能获得完整内置体验这一事实意味着,通常可以假定他们已在计算机上安装 Silverlight 3 运行库。如果计划使用 Silverlight 4 而不是 Silverlight 3,则必须假定用户愿意并且能够在计算机上安装 Silverlight 的更新版本。

在 JavaScript 和 Silverlight 之间做出选择时要考虑的最后一点与开发人员工作效率相关。在这一方面,Silverlight 开发明显更胜一筹。这是因为您可以在 Visual Studio 2010 中工作并使用 C# 或 Visual Basic 编写代码。调用 .NET Framework 和客户端对象模型中的方法时,您可以体验编译时类型检查和 IntelliSense 的所有好处。还可以创建服务引用,从而大大简化针对 Web 服务(如 ListData.svc)进行编程。

在 Visual Studio 2010 中对 JavaScript 进行编程的体验与对 Silverlight 应用程序进行编程的体验完全不同。没有编译时类型检查,针对客户端对象模型进行编程时也没有任何 IntelliSense。此外,还需要掌握 JavaScript 和 ASP.NET AJAX 的高级编程技能,才能调用 Web 服务(如 ListData.svc)或者在更新 UI 中的内容之前从回调方法执行所需的线程切换。如果您刚刚开始学习编写客户端代码,则与使用 JavaScript 编写代码相比,使用 Silverlight 开发是更好的选择。

结论

本文讨论了 SharePoint 2010 开发中的主要设计决定。您了解了为什么以及什么时候应该面向沙盒,以及什么时候应该创建需要服务器场级部署的 SharePoint 解决方案。您还了解了决定使用 Web 部件、网站页面和应用程序构建自定义 UI 时要考虑的问题。

本文还讨论了使用服务器端对象模型和客户端对象模型的不同应用场景。您可以看出这实际上取决于特定应用场景的细节以及应用场景是否需要客户端代码。您还了解了,针对 SharePoint 对象进行编程和查询列表时,服务器端代码和客户端代码各自的特定优势。有一点很明显,那就是 SharePoint 开发人员现在编写的客户端代码比过去多很多。

其他资源

有关详细信息,请参阅以下资源:

关于作者

MVP 参与者Ted Pattison 是一位作家兼讲师,同时也是专门从事 SharePoint 技术培训的 Critical Path Training(该链接可能指向英文页面) 公司的共同创始人。作为 Microsoft SharePoint 最有价值的专家 (MVP),Ted 经常与 Microsoft Developer Platform Evangelism 小组合作,以便在产品生命周期的 Alpha 和 Beta 阶段及早进行研究并为开发人员创作 SharePoint 培训材料。Ted 还是 Inside Microsoft SharePoint 2010(该链接可能指向英文页面) 一书的合著者。