Office 加载项

在 Office 2010 中访问 SharePoint 数据的三种解决方案

Donovan Follette

下载示例代码

数百万的人在使用 Microsoft Office 客户端应用程序开展日常工作,用于通信、清理数据、处理数字、编写文档、提交演示文稿以及制定业务决策。在日益增长的用户群体中,许多人与 Microsoft SharePoint 交互,将其用作协作门户以及访问共享数据和服务的平台。

有些企业的开发人员尚未充分利用这个机会在 Office 应用程序中构建自定义功能,在熟悉的生产应用程序内直接访问 SharePoint 数据,从而提供流畅的集成式用户体验。企业考虑提高最终用户工作效率的途径时,可以重点考虑直接在 Office 应用程序中访问 SharePoint 数据的方法。

在 SharePoint 2010 发行版中,可以采用一些新的途径来访问 SharePoint 数据并将其呈现给 Office 用户。这些途径包括:通过 SharePoint Workspace 2010(以前称为 Groove)实现的几乎无需编写代码的解决方案,SharePoint 与 Outlook 的直接同步,新的 SharePoint REST API,以及新的客户端对象模型。正如在 Microsoft Office SharePoint Server (MOSS) 2007 中一样,SharePoint 2010 中也有大量的 Web 服务可供使用。

本文将介绍几种无需编写代码的解决方案,并向您演示如何使用 SharePoint 2010 中的这些新增功能来构建几个更加复杂的解决方案。

外部数据源

首先,我们快速浏览一下可用作数据源的 SharePoint 列表类型。

特别有用的一种数据源是外部列表,用来显示那些通过业务线 (LOB) 系统连接检索的数据。在 MOSS 2007 中,可以使用业务数据目录 (BDC) 连接到 LOB 数据,提供对后端系统的只读访问权限。SharePoint 2010 提供了 Business Connectivity Services (BCS),BCS 是 BDC 的升级版,支持对 LOB 数据的完整读/写访问。

为什么要将 LOB 数据引入 SharePoint 中?考虑以下使用情形:您有客户关系管理 (CRM) 系统,而您的组织中只有有限的几个人可以直接访问该系统。然而,数据库中可能有一个客户表包含其名称和地址数据,可供其他许多人使用。在现实生活中,最后很可能是,用户从各种非权威来源复制此类信息,并将其粘贴到 Office 文档中。但最好能从权威的 CRM 系统中访问此类客户数据,并将其作为可从 Office 客户端访问的外部列表显示在 SharePoint 中。

SharePoint Designer 2010 工具用来配置对 LOB 系统的访问权限,并在 SharePoint 外部列表中提供其数据。要做到这一点,需要执行几个步骤。

第一步是创建新的外部内容类型 (ECT)。ECT 包含一些描述后端数据结构的元数据,例如字段和 CRUD 方法,SharePoint 将使用这些元数据与其进行交互。一旦创建了 ECT,即可根据它在 SharePoint 内的任意站点上生成外部列表。外部列表与 SharePoint 中其他任何标准列表的表现基本一样,只不过外部列表数据并不存储在 SharePoint 中,而是在最终用户访问这些数据时从 ECT 中检索的。

SharePoint Designer 默认情况下支持连接到外部数据源,包括 SQL Server、Windows Communication Foundation (WCF) 以及 Microsoft .NET Framework。因此,可以轻松创建 ECT 来连接到任意 SQL Server 数据库表/视图、WCF 服务或 Web 服务。在 Visual Studio 2010 中,可以使用新的 SharePoint 2010 项目模板“业务数据连接模型”来构建自定义 .NET 解决方案。

就本文而言,我们使用了 SQL Server 数据源类型为数据库表创建 ECT。然后使用该 ECT 创建外部列表。图 1 显示了在完成 SharePoint Designer 中的配置后得到的 ECT“Customers From CRM”。

图 1 用于访问外部 CRM 数据的 ECT 配置

在此要指出几个问题。首先要注意,在“外部内容类型信息”面板中,“Office 项类型”属性值设为“联系人”。在配置过程中,可以将外部数据字段映射至相应的 Office 项类型,如“联系人”。这不是必需的,但是由于 CRM 数据库中的姓名和地址数据可以精确映射至 Outlook 联系人,因此选择了这一方式。以后,您就可以在 Outlook 中使用此配置选项的结果。

其次要注意,在“外部内容类型操作”面板中,为此 ECT 启用了完整的 CRUD 方法。这是由配置向导中所做的选择导致的。但是当然也可能有一些业务原因,会将 LOB 系统操作限制为只读。在这种情况下,在配置过程中可以只选择“读取列表”和“读取项”操作。只有这两项操作是创建 ECT 时所必需的。

一旦创建了 ECT,根据它来创建外部列表就很简单了,只需要在 SharePoint 或 SharePoint Designer 内创建一个新的外部列表。

SharePoint 标准列表

当然,您可以采用标准的 SharePoint 列表来显示业务数据。例如,假设您所在的部门管理着培训课程内容。您维护两个 SharePoint 列表:“课程类别”和“课程”。这两个列表包含课程信息,其他团队的员工利用这些信息来创建客户通信、宣传手册或广告活动。因此,数据虽由一个小组来维护,但必须随时可供整个公司中的许多人员使用。

SharePoint 2010 具有一项新增功能,可用来查找列表之间的关系。在列表中创建一个新列时,有一个选项是将该列设为查找类型,然后指定站点内的另一个列表作为其数据源。SharePoint 支持针对一对多关系的单值查找,也支持针对多对多关系的多值查找。SharePoint 还可以根据您的选择在支持受限删除或级联删除的列表之间维护引用完整性。这就为您在 SharePoint 中如何设置和使用列表提供了一些选择。

就我们的示例而言,您可以轻松创建一个名为“类别”、数据源为“课程类别”列表的“课程”列表查找列,如图 2 所示。

图 2 使用以“课程类别”为数据源的查找列表

将 SharePoint 列表数据引入 Office 中

迄今为止,我们了解了如何使用 SharePoint 2010 中新增的 BCS 功能,将外部数据显示为 SharePoint 列表。用户可以通过 PC 或移动设备上的浏览器来访问数据,但用户可能会更喜欢完整的 Office 客户端应用程序的丰富体验。现在,我们把关注点转向通过两种途径在客户端上使用 SharePoint 列表数据。首先,我们将介绍如何利用 SharePoint Workspace 和 Outlook 来访问数据,而无需编写任何代码。

在开发 CRM 解决方案示例时,SharePoint 功能区有两个连接和导出按钮可用于外部客户列表:“同步到 SharePoint Workspace”和“连接到 Outlook”(请参见图 3)。如果 SharePoint Workspace 2010 安装在客户端计算机上,则单击一次“同步到 SharePoint Workspace”按钮即可将列表和文档库同步到客户端。SharePoint Workspace 中的用户随后就可以使用本地缓存的内容副本,而无论用户是否联机。如果用户在处于脱机状态时修改了某个列表项或文档并保存在本地,则当用户再次联机时,该列表项或文档将自动与 SharePoint 同步。

图 3 SharePoint 功能区中的连接和导出选项

这是一种无需编写代码的解决方案。数据可在 SharePoint Workspace 客户端应用程序中访问,如图 4 所示。由于在 ECT 中定义了完整的 CRUD 方法,在 SharePoint Workspace 中对客户数据所做的任何更改也都会在 CRM 数据库中更新。

图 4 在 SharePoint Workspace 中访问外部列表数据

由于我们在 ECT 配置过程中将 CRM 数据库字段映射至 Office 项类型“联系人”,因此 SharePoint 可以将外部列表数据作为自有的联系人项提供给 Outlook。通过单击功能区上的“连接到 Outlook”按钮,SharePoint 将使这个外部列表直接同步到 Outlook 中。同样,也无需编写代码,就能将 SharePoint 数据传送到 Office 客户端。

使用 REST API

无需编写代码的解决方案(例如通过 SharePoint Workspace 和 Outlook 列表连接功能实现的那些解决方案)固然方便,但有些用户体验需要更具针对性的解决方案。为了适应这些要求,我们需要在 Office 应用程序中提供对列表数据的访问权限,从而使我们能够进一步自定义解决方案。

开发人员访问 SharePoint 列表和文档库数据的最方便的途径或许是通过新的 REST API (listdata.svc)。SharePoint 中的大部分数据表现为支持 REST 的端点。SharePoint 服务的标准位置是 _vti_bin,因此如果仅在浏览器中输入站点的 URL 并附加 /_vti_bin.listdata.svc,您将获得一个标准的 ATOM 服务文档,其中描述了站点上提供的集合(请参见图 5)。

图 5 ATOM 服务文档

请注意,“课程”和“课程类别”列表已经存在。如果您在 URL 中进一步附加 /Course,则可以检索列表中的所有课程;而通过附加数字,则可以检索特定的课程。例如,输入以下内容将返回第三课:

http://intranet.contoso.com/sites/SPC/_vti_bin/listdata.svc/Course(3)

通过附加以下属性筛选器,您可以执行更高级的查询:

?$filter=startswith(propertyname,'value')

但此处的一个重要高级查询可以返回课程及其关联的课程类别数据。通过在站点 URL 后附加以下内容,您可以在单个负载中检索课程和课程类别的组合结构:

/_vti_bin.listdata.svc/Course?$expand=Category

在下一部分中,您将看到如何在 Word 加载项中实现此查询。

构建 Word 加载项

当您了解了如何利用 REST API 获取对数据的访问权限后,就可以在用户有丰富创作经验的客户端应用程序中显示数据。在此示例中,我们将构建一个 Word 加载项,以一种有意义的方式将数据呈现给用户。此应用程序将有一个下拉列表,其中包含课程类别;一个列表框,其中加载了与类别选择相对应的课程;以及一个按钮,用于将课程相关文本插入 Word 文档中。

在 Visual Studio 2010 中,使用 C# 创建新的 Office 2010 Word 加载项项目。

现在,添加一个新的服务数据源。在向导的“添加服务引用”面板中,输入您的 SharePoint 站点的 URL,并附加 /_vti_bin/listdata.svc。例如,

http://intranet.contoso.com/_vti_bin/listdata.svc

输入 URL 后,单击“转到”。这将检索 SharePoint 站点的元数据。当您单击“确认”时,WCF 数据服务将通过使用实体框架为您生成强类型化的类。这完全屏蔽了以下事实:数据源是 SharePoint 或通过开放数据协议提供数据的 OData 生成器。从这里开始,使用数据不过就是使用熟悉的 .NET 类而已。

对于 UI,将创建一个自定义任务窗格,从而在 Office 应用程序中提供一个可以停靠在应用程序顶部、底部、左侧或右侧的 UI。任务窗格中可以添加 Windows 窗体控件,包括此处使用的 Windows Presentation Foundation (WPF) 用户控件。

使用“添加新项”对话框在项目中添加一个 WPF 用户控件,并将其命名为 CoursePicker。当设计器打开后,将 Grid 元素替换为图 6 所示的 XAML 代码段。这将添加 ComboBox、Button 和 ListBox,并且为它们设置一些属性。以后需要添加几个事件。

图 6 Word 加载项 UI 标记

<StackPanel>

  <ComboBox 

    Name="cboCategoryLookup" Width="180" Margin="5" 

    HorizontalAlignment="Center" IsEditable="False" 

    ItemsSource="{Binding}"    

    DisplayMemberPath="CategoryName" 

    SelectedValuePath="CategoryName" />

  <Button Name="button1" 

    Content="Insert Course Information" Margin="5" />

  <ListBox Name="courseListBox" ItemsSource="{Binding}">

    <ListBox.ItemTemplate>

      <DataTemplate>

        <StackPanel>

          <StackPanel Orientation="Horizontal">

            <TextBlock Text="{Binding Path=CourseID}" 

              FontWeight="Bold" />

            <TextBlock Text=": " FontWeight="Bold" />

            <TextBlock Text="{Binding Path=Name}" />

          </StackPanel>

          <TextBlock Text="{Binding Path=Description}" 

            Margin="5 0 0 0" />

        </StackPanel>

      </DataTemplate>

    </ListBox.ItemTemplate>

  </ListBox>

</StackPanel>

打开 CoursePicker.xaml.cs 文件。在紧接在命名空间之后的位置,添加两个 using 语句,一个用于服务引用 ServiceReference1,另一个用于 System.Net:

namespace Conf_DS {

    using ServiceReference1;

    using System.Net;

在 CoursePicker 类中,第一步是实例化数据上下文对象。在此传入站点的 URL,并在其后附加 _vti_bin/listdata.svc 定义:

public partial class CoursePicker : UserControl {

  Office2010DemoDataContext dc = new Office2010DemoDataContext(

    new Uri("http://intranet.contoso.com/sites/spc/_vti_bin/listdata.svc"));

接下来,您会得到一个 List 类级别变量,用于缓存所检索的课程项并将其存回服务器上:

List<CourseItem> courses = null;

用来检索课程和课程类别数据的代码位于重写方法 OnInitialized 中。首先,您指定自己的登录凭据以传递给服务器。然后,将通过数据上下文对象检索课程类别并将其绑定到类别 ComboBox。最后,由于采用了扩展选项,因此将返回课程及其关联的类别,并将课程加载到课程列表对象中。这样将在本地缓存课程,以获得更好的性能:

protected override void OnInitialized(EventArgs e) {

    dc.Credentials = CredentialCache.  

  DefaultCredentials;



    // Load Category dropdown list

    cboCategoryLookup.DataContext =  

      dc.CourseCategory;

    cboCategoryLookup.SelectedIndex = 0;



    // To cache data locally for courses 

    // Expand to retrieve the Category as well.

    courses = dc.Course.Expand("Category").ToList();



    base.OnInitialized(e);

  }

现在,您需要添加几个事件。回到 CoursePicker 设计器中,并双击相应的按钮来创建按钮单击事件。接下来,单击 ComboBox,然后在属性菜单中单击“事件”选项卡,并双击 SelectionChanged 事件。向 SelectionChanged 事件处理程序中添加代码,使其如下所示:

private void cboCategoryLookup_SelectionChanged(

  object sender, SelectionChangedEventArgs e) {



  courseListBox.DataContext = from c in courses

    where c.Category.CategoryName == cboCategoryLookup.SelectedValue.ToString()

    orderby c.CourseID

    select c;

}

此处有一个简单的 LINQ 查询,用于搜索课程列表对象(即,与使用扩展选项检索的数据一起加载的对象),以找出具有以下特征的所有课程:其类别名称与 ComboBox 中所选课程类别的名称匹配。该查询还将对结果进行排序,以提供清晰的用户体验。

最后,向按钮事件处理程序中添加代码,以便将所选的列表框项的类型转换为 CourseItem 对象。然后,按照您的需要将各种数据元素呈现给用户,并将这些元素放到文档中的插入点处:

private void button1_Click(

  object sender, RoutedEventArgs e) {



  CourseItem course = (CourseItem)courseListBox.SelectedItem;

  Globals.ThisAddIn.Application.Selection.InsertAfter(

    String.Format("{0}: {1} \n{2}\n", course.CourseID, 

    course.Name, course.Description));

}

就是这样了,通过 WCF 数据服务访问 SharePoint 中的数据的代码真的很简单。

现在打开 ThisAddIn.cs 文件。这是所有 Office 加载项的主要入口点。您要再次添加代码以实例化任务窗格:

private void ThisAddIn_Startup(object sender, System.EventArgs e) {



  UserControl wpfHost = new UserControl();

  ElementHost host = new ElementHost();

  host.Dock = DockStyle.Fill;

  host.Child = new CoursePicker();

  wpfHost.Controls.Add(host);

  CustomTaskPanes.Add(wpfHost, "Training Courses").Visible = true;

}

CoursePicker WPF 用户控件不能直接添加到自定义任务窗格对象集合中,而必须驻留在 ElementHost 控件中,该控件是 WPF 控件与 Windows 窗体控件之间的桥梁。请注意,CoursePicker 对象将作为 ElementHost 对象的子对象来添加,然后 ElementHost 对象会被添加到自定义任务窗格对象集合中。Office 应用程序中可以安装多个自定义任务窗格,并在任意给定时间供用户使用,因此这个加载项的任务窗格仅仅是集合中的一个对象。图 7 显示了已完成的加载项。

图 7 工作中的 Word 加载项

数据显示在 Office 应用程序中时,您就可以通过添加与 Word API 交互的代码来改进解决方案。例如,您可以添加代码,以便在用户选择课程后,就在文档中插入相关信息并设定其格式。Office 应用程序 API 非常丰富,可以向您的自定义解决方案中添加更多功能,从而进一步提高用户的工作效率。接下来,我们将看一个这样的示例,其中的 Word 内容控件与客户端 SharePoint 对象模型相连。

使用客户端对象模型

使用 REST API 获取数据访问权限是可供您选择的方式之一。例如,还有三个新的 API 可用于 SharePoint 2010,它们在 JavaScript、.NET 托管应用程序和 Silverlight 客户端中提供了一致的编程模型。这三种客户端对象模型使用服务器对象模型的部分功能与 SharePoint 交互,主要在站点集合级别及其下级别(Web、列表、列表项、内容类型、字段和外部列表等)与 SharePoint 进行互操作。如果您熟悉服务器对象模型,也就会熟悉客户端对象模型。

为了演示客户端对象模型的用法,我们将使用包含 CRM 客户的外部列表来构建文档级别的 Word 加载项,其中随客户一起加载了操作窗格。在这种情况下,您需要使用客户端对象模型,因为列表数据服务不提供对外部列表的访问权限。在此示例中,用户可以选择一个客户,将其名称和地址信息插入报价文档模板的内容控件中。

上一个“课程和类别”示例是一个应用程序级别的加载项。应用程序级别的 Word 加载项在 Word 每次启动时均会出现。但文档级别的加载项则绑定到一个文档,仅在特定类型的文档打开时才会加载。在这种情况下,仅在用户处理报价文档时,外部客户列表才会呈现给用户。

在 Visual Studio 中,首先创建一个新的 Word 2010 文档项目。您需要在向导中选择默认文档或某个已保存的文档。在我的示例中,我使用的是一个已保存的报价文档。该文档将在 Visual Studio 内打开,而 Word 将成为文档设计器。

您可以使用工具箱直接将控件放到文档图面上,就像在 Windows 窗体应用程序中那样。在此添加用于名称和地址信息的 Word 内容控件。这些内容控件中填充的数据将来自用户在运行时选择的客户。

若要向文档中添加内容控件,请在文档中选择您要包含到内容控件中的文本。然后,在工具箱中拖动 Word 控件中的 RichTextContentControl,并将其放到所选的文本上。然后为控件指定名称,并在“属性”中提供文本值。对客户和公司名称、地址、所在城市以及客户 ID 执行上述操作,使文档如图 8 所示。

图 8 创建报价文档

由于客户端对象模型不提供来自服务器的强类型化数据,因此您需要向项目中添加一个 Customer 类。该 Customer 类用于映射客户端对象模型所返回的数据:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;



namespace CSOM_Quote {

  public class Customer     {

    public string CustomerID { get; set; }

    public string CompanyName { get; set; }

    public string ContactName { get; set; }

    public string Address { get; set; }

    public string City { get; set; }

  }

}

若要使用客户端对象模型,需要引用 Microsoft.SharePoint.Client 和 Microsoft.SharePoint.Client.Runtime。

正如上一个示例所示,数据检索操作在 OnIntitialized 重写方法中执行。客户端对象模型编程与 WCF 数据服务编程有几个重要差别。首先,客户端对象模型假定您熟悉 SharePoint 及其结构。而使用 WCF 数据服务,则没有上述要求,您只需对数据进行操作即可。其次,使用客户端对象模型时,返回的数据不是强类型化的。您需要自行将数据整理到可用于 LINQ 查询和数据绑定的对象中。

数据访问代码如图 9 所示。客户端上下文是此处的核心对象。传递站点 URL 以创建新的客户端上下文实例。然后即可开始创建 SharePoint 对象,操作步骤如下:

  1. 创建站点
  2. 创建站点列表集合
  3. 获取具有特定名称的列表
  4. 获取该列表中的所有项
  5. 将查询加载到上下文中
  6. 执行查询

图 9 CRM 加载项的数据访问代码

protected override void OnInitialized(EventArgs e) {

  SPClientOM.ClientContext context =  new ClientContext("http://intranet.contoso.com/sites/spc");

  SPClientOM.Web site = context.Web;

  SPClientOM.ListCollection lists = site.Lists;

  var theBCSList = lists.GetByTitle("Customers");

  SPClientOM.CamlQuery cq = new SPClientOM.CamlQuery();

  IQueryable<SPClientOM.ListItem> bcsListItems =  theBCSList.GetItems(cq);

  bcsList = context.LoadQuery(bcsListItems);

  context.ExecuteQuery();



  var bcsCustomerData = 

    from cust in bcsList

    select new Customer {

      CustomerID = cust.FieldValues.ElementAt(1).Value.ToString(),

      ContactName = cust.FieldValues.ElementAt(2).Value.ToString() 

        + " " 

        + cust.FieldValues.ElementAt(3).Value.ToString(),

      CompanyName = cust.FieldValues.ElementAt(4).Value.ToString(),



      Address = cust.FieldValues.ElementAt(5).Value.ToString(),

      City = cust.FieldValues.ElementAt(6).Value.ToString(),  };



  foreach (var x in bcsCustomerData)  {

    Customer tempCustomer = new Customer();

    tempCustomer.CustomerID = x.CustomerID;

    tempCustomer.CompanyName = x.CompanyName;

    tempCustomer.ContactName = x.ContactName;

    tempCustomer.Address = x.Address;

    tempCustomer.City = x.City;



    customers.Add(tempCustomer);

  }



  customerListBox.DataContext = customers;

  base.OnInitialized(e);

}

在调用 ExecuteQuery 方法之前,先前的所有语句都将排队等候,仅在随后执行查询时才会传送至服务器。这样,您就能控制带宽和负载。一旦查询返回了结果,其余代码会将数据映射到一个客户列表对象中,而该对象可以绑定到客户列表框控件。 

此示例中还使用了 WPF 用户控件。这是因为 XAML 与上一个示例相似,此处不再另行解释。但是,用于实例化文档级别的操作窗格而非应用程序级别的任务窗格的代码稍有不同,如下所示:

public partial class ThisDocument {

  private CustomersCRM CustomerActionPane =  new CustomersCRM();



  private void ThisDocument_Startup(object sender, System.EventArgs e) {

    ElementHost host = new ElementHost();

    host.Dock = DockStyle.Fill;

    host.Child = new CustomerPicker();

    CustomerActionPane.Controls.Add(host);

    this.ActionsPane.Controls.Add(CustomerActionPane);

  }

...

请注意,客户选择器 WPF 用户控件将添加到 ElementHost 中,ElementHost 对象将添加到客户操作窗格中,然后客户操作窗格将添加到操作窗格控件集合中。

最后一步是添加按钮单击事件,以便在 Word 内容控件中填充适当的名称和地址信息,如图 10 所示。

图 10 向 Word 内容控件中添加按钮单击事件

private void button1_Click(

  object sender, RoutedEventArgs e) {

  Customer customer = (Customer)customerListBox.SelectedItem;



  Globals.ThisDocument.wccContactName.Text = customer.ContactName;

  Globals.ThisDocument.wccCompanyName.Text = customer.CompanyName;

  Globals.ThisDocument.wccAddress.Text = customer.Address;

  Globals.ThisDocument.wccCity.Text = customer.City;

  Globals.ThisDocument.wccCustomerID.Text = customer.CustomerID;

}

首先,您将所选的列表框项的类型转换为客户对象。然后,来自客户对象的数据会被用来填充内容控件。所得结果如图 11 所示。

图 11 Word 内的 CRM 加载项

Web 服务用作社交服务

到目前为止,您已经看到了几种在 Office 客户端应用程序中访问 SharePoint 数据的方式。我们要了解的最后一项技术是使用 Web 服务。SharePoint 提供了 Web 服务来作为远程访问 SharePoint 数据的主要方式。通过 SharePoint 2010 中的 Web 服务,您可以访问 SharePoint Server 中几乎所有的功能。与您已了解的其他一些数据技术(例如 REST 和客户端对象模型)不同的是,Web 服务既可用于访问数据,也可用于访问管理功能。

您喜欢的所有 Web 服务仍然能够使用,例如 Lists.asmx 和 Search.asmx services。SharePoint Web 服务将作为 ASP.NET Web 服务实现,其扩展名为 .asmx;SharePoint 2010 中的大多数新增服务也作为 ASMX 服务编写。这样做主要是为了最大程度上与其他产品和工具兼容。

关于 SharePoint Web 服务的新关注点是社交服务。所有社交应用程序均以用户为中心。SharePoint 具有 UserProfileService,可用于访问用户的所有个人资料信息。UserProfileService 包含诸如姓名和地址之类的标准属性,还包含其他一些属性,例如爱好、技能、学校和伙伴等。“伙伴”(在其他的公共社交网站中叫作“好友”)是 SharePoint 社交结构的一项关键功能。

社交应用程序的另一个重要方面是用户如何评价他们看到的内容。SharePoint 具有 SocialDataService,使用户能够对站点内的数据、文档和页面进行标记、分级和评论。

SharePoint 的第三个重要社交方面是发布活动以及订阅伙伴发布的活动。SharePoint 提供了 ActivityFeed 和 API,以订阅源的形式来发布活动。

由于本文的主题不是 SharePoint 中的新增社交功能,所以我们不会深入讨论这些功能,但是它们为本文后面的示例提供了一些重要的上下文。有关详细信息,请参见 SharePoint 开发人员中心或“使用 Microsoft Office SharePoint Server 2007 管理社交网络”白皮书。

通过 Web 服务扩展 Outlook

我们已经看到,当您确定在 Office 应用程序中访问数据的最佳方式时,SharePoint 和 Office 提供非常多的选择。另一种方式涉及使用 SharePoint Web 服务。在此示例中,我们将创建一个新的 Outlook 功能区,使您可以将所有 SharePoint 伙伴作为联系人项添加到 Outlook 中。您甚至能够将用户的个人资料图片显示在 Outlook 中,就像您在 Microsoft Exchange 所提供的联系人中惯常看到的那样。

首先在 Visual Studio 2010 中创建一个新的 Outlook 加载项。我们打算用 C# 来编写,但如果您愿意,也可以使用 Visual Basic。在以前的版本中,Visual Basic 在支持可选参数等功能方面略占优势,但是现在 C# 也支持这些功能。

功能区提供了一致、简便的方式与所有 Office 应用程序进行交互。Outlook 2010 当前包含一个用于主屏幕的功能区。在此示例中,将在此添加一个新的功能区。在 Visual Studio 2010 中,可以使用一个直观的功能区设计器轻松创建 Office 功能区。您只需将控件从左侧的工具箱拖放到设计图面即可。

在此示例中,您只需设置几个属性,例如选项卡和组标签。然后,在图面中添加一个按钮控件。一旦在功能区组中添加了按钮,您就可以设置按钮的大小并添加按钮图像。该功能区将类似图 12 所示。

图 12 创建新的 Outlook 功能区

最后一步是设置相应的属性来确定何时显示功能区。默认情况下,功能区显示在邮件资源管理器中。当您打开邮件项时会看到该窗口。在此示例中,您希望功能区显示在主屏幕上。选择该功能区,然后将 RibbonType 属性设为 Microsoft.Outlook.Explorer。您可以看到,可显示功能区的位置有很多,包括邮件资源管理器和联系人资源管理器。

接下来,双击功能区按钮,以创建代码隐藏的单击事件处理程序。您将需要使用该事件来创建 Outlook 联系人。

现在,您就可以添加代码在 Outlook 中创建联系人了。在 Visual Studio 2010 中可以轻松完成此操作。我发现,如果把问题分成较小的几个部分,会比较容易解决。首先,您创建了 Outlook 加载项,然后创建了功能区。完成所有这些步骤后,确认按 F5 键来编译和运行应用程序。现在就可以使用硬编码的值来创建 Outlook 联系人了。如果您证实此操作有效,就可以添加代码来调用 SharePoint。同样,请在完成每一步后确认一切正常,然后再执行下一步。

图 13 显示了用于创建新的硬编码联系人的代码。此代码使用 CreateItem 方法来创建新的 ContactItem 对象。然后,您可以设置 ContactItem 的属性,并调用 Save 方法来提交所做的更改。

图 13 用于创建联系人的示例代码

Outlook.ContactItem newContact = Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olContactItem);



newContact.FirstName = "Paul";

newContact.LastName = "Stubbs";

newContact.Email1Address = "pstubbs@microsoft.com";

newContact.CompanyName = "Microsoft";

newContact.JobTitle = "Technical Evangelist";

newContact.CustomerID = "123456";

newContact.PrimaryTelephoneNumber = "(425)555-0111";

newContact.MailingAddressStreet = "1 Microsoft Way";

newContact.MailingAddressCity = "Redmond";

newContact.MailingAddressState = "WA";

newContact.AddPicture(@"C:\me.png");

newContact.Save();

唯一真正棘手的问题是,设置联系人图片的方式是调用 AddPicture 方法,该方法采用磁盘上图片路径。这之所以成问题是因为您希望从 SharePoint 中获取图像。在下一部分中,您将看到如何执行此操作。一旦您证实代码有效并已在 Outlook 中创建了联系人,就随时可以调用 SharePoint 并添加真正的联系人。

使用用户个人资料服务

UserProfileService 是一种 SharePoint Web 服务,您可以用来访问个人资料信息,包括您的伙伴及其个人资料信息的列表。若要使用此服务,应首先向项目中添加引用。由于此服务是 Web 服务而非 WCF 服务,因此您需要单击“添加服务”对话框的“高级”选项卡,然后单击“添加 Web 服务”按钮。这里打开的“添加 Web 服务”对话框与您在 Visual Studio 2005 中所熟悉的对话框一样。

添加完引用后,您就可以添加代码来检索伙伴信息:

// Instantiate the Web service.

UserProfileService userProfileService = new UserProfileService();



// Use the current user log-on credentials.

userProfileService.Credentials = System.Net.CredentialCache.DefaultCredentials;

此代码可创建一个服务实例,并将您当前的凭据传递给服务。接下来,调用 GetUserColleagues 方法以传递您想要检索其伙伴信息的用户。这将返回一个 ContactData 对象数组:

ContactData[] contacts = userProfileService.GetUserColleagues("contoso\\danj");

现在我们就可以遍历所有 ContactData 对象,这些对象表示 SharePoint 中的用户伙伴的个人资料信息。我们通过调用 GetUserProfileByName 方法来检索扩展属性,这将返回一个 PropertyData 对象数组,其中包含每个伙伴的键/值对:

// Add each Colleague as an Outlook Contact

foreach (ContactData contact in contacts) {

  // Get the users detailed Properties

  PropertyData[] properties = userProfileService.GetUserProfileByName(contact.AccountName);



  // Create a new Outlook Contact

  Outlook.ContactItem newContact = Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olContactItem);

现在,我们将键/值对转换成联系人属性:

// Set the Contact Properties

newContact.FullName = contact.Name;

newContact.FirstName = properties[2].Values[0].Value.ToString();

newContact.LastName = properties[4].Values[0].Value.ToString();

newContact.Email1Address = properties[41].Values[0].Value.ToString();

...

最后,抓取联系人照片并保存新联系人:

// Download the users profile image from SharePoint

SetContactImage(properties, newContact);



newContact.Save();

最后一个难题是从 SharePoint 中检索联系人的图片。某个扩展属性中包含用户个人资料图片缩略图的路径。您需要将此图片下载到磁盘上的某个临时文件中,以便 Outlook API 将其添加到 ContactItem 对象中:

private static void SetContactImage(

  PropertyData[] properties, 

  Outlook.ContactItem newContact){



  // Download image to a temp file

  string userid = properties[16].Values[0].Value.ToString();

  string imageUrl = properties[15].Values[0].Value.ToString();

  string tempImage = string.Format(@"C:\{0}.jpg", userid);

  WebClient Client = new WebClient();

  Client.Credentials = CredentialCache.DefaultCredentials;

  Client.DownloadFile(imageUrl, tempImage);

  newContact.AddPicture(tempImage);

}

就是这样了!现在您就有了一个 Outlook 加载项功能区,用于调用 SharePoint,以将社交数据添加到 Outlook 联系人中。当您运行应用程序时,将看到一个 ContactItem 对象,其中填充了 SharePoint 数据,包括用户的个人资料信息和图像。

总结

现在您已经看到,从 SharePoint 向 Office 客户端获取数据是多么简单。我们已向您展示了各种不同的方式,从无需编写代码的解决方案,到使用 C# 或 Visual Basic 的高适应性解决方案。

使用 WCF 数据服务访问 SharePoint 列表数据,为 .NET 开发人员提供了一种通用模式,可以方便、快捷地实现。客户端对象模型提供了访问 SharePoint 外部列表的方法,并使您有可能将 LOB 数据引入 Office 中。最后,SharePoint Web 服务实现了最灵活的数据访问,但是在编写代码和测试方面,还有待进一步提高。

将 SharePoint 中的数据作为列表供用户使用是一个重要步骤,因为这可以在浏览器中实现非凡的用户体验。再进一步,您可以充分利用各种数据访问方式,以便随后将数据引入用户所熟悉的 Office 应用程序中。Visual Studio 2010 大大简化了所有这些构建、调试和部署过程。正如您所见,这些是您在新的产品发行版中可以利用的部分新增的重要开发功能。

如需更多培训、示例和信息,请访问 Office 和 SharePoint 开发人员中心。

Donovan Follette 是一位 Microsoft 技术推广专家,主要推广以下技术:Active Directory、轻型目录服务和 Active Directory 联合身份验证服务。目前,他主要从事 Office 开发以及使用 SharePoint 2010 构建集成解决方案。您可以通过以下网址访问他的博客:blogs.msdn.com/b/donovanf/

Paul Stubbs 也是一位 Microsoft 技术推广专家,主要从事 SharePoint 和 Office、Silverlight 和 Web 2.0 社交网络的信息工作者开发社区方面的工作。他编写过三本关于使用 Office、SharePoint 和 Silverlight 开发解决方案的图书。您可以通过以下网址阅读他的博客:blogs.msdn.com/b/pstubbs/

*衷心感谢以下技术专家审阅本文:*John Durant