在提供程序托管的加载项中添加自定义按钮

这是关于开发 SharePoint 托管的 SharePoint 加载项的基础知识系列文章中的第 3 篇文章。你应该首先熟悉 SharePoint 加载项以及本系列中之前的文章(可在创建提供程序托管的 SharePoint 加载项入门中找到相关内容)。

注意

如果已完成有关提供商托管加载项的本系列文章之一,便已生成 Visual Studio 解决方案,可以在继续阅读本主题的过程中使用。 也可以从 SharePoint_Provider-hosted_Add-Ins_Tutorials 下载存储库,再打开 BeforeRibbonButton.sln 文件。

SharePoint 加载项可以包含自定义操作,这就是 SharePoint 领域提到的自定义菜单项或功能区按钮一词。 本文将介绍如何创建自定义按钮,以同步 SharePoint 列表与远程数据库。

在主机网站上创建自定义列表

自定义按钮将位于记录本地分店的员工的特定列表的功能区上。 在本系列的后续文章中,您将了解如何以编程方式将自定义列表添加到主机网站,但现在您需要手动添加。

  1. 在 Fabrikam 香港店的主页中,依次转到“网站内容”>“添加加载项”>“自定义列表”

  2. 在“添加自定义列表”对话框中,指定“本地员工”作为名称,再选择“创建”

  3. 在“网站内容”页上,打开“本地员工”列表。

  4. 在功能区的“列表”选项卡上,选择“列表设置”

  5. 在“列表设置”页的“列”部分中,选择“称呼”列。

  6. 在“编辑列”表单中,将“列名称”从“称呼”更改为“姓名”,再选择“确定”

  7. 在“设置”页上,选择“创建列”

  8. 在“创建列”表单中,执行下列操作:

    1. 对于“列名称”,输入“添加到企业 DB”
    2. 将“类型”设置为“是/否(复选框)”
    3. 将“默认值”设置为“否”
    4. 选择“确定”。 此时,将返回到“设置”页。
  9. 选择“网站内容”,打开“网站内容”页。 其中已有新列表的磁贴。 打开它。

  10. 单击“新建项”,并在项创建表单中输入姓名,但不要选中“添加到企业 DB”。 选择“保存”。 此时,列表应如下所示。

    图 1. 包含单个项目的本地员工列表

    包含一个项的“本地员工”列表,其中“姓名”列的值为“Brayden Sawtell”,“添加到企业 DB”列的值为“否”。

添加自定义按钮

此部分将介绍如何在加载项中添加标记,从而将按钮部署到列表的功能区。 如果用户选中列表中的员工并选择此按钮,相应员工的姓名便会添加到企业数据库中,并且相应员工的“添加到企业 DB”字段也会从“否”切换为“是”

  1. 如果 Visual Studio 已打开,必须关闭并重新打开连锁店解决方案,这样 Visual Studio 才能发现新列表(以管理员身份运行 Visual Studio)。

    注意

    只要重新打开解决方案,Visual Studio 中的“启动项目”设置往往会还原为默认值。 重新打开本系列文章中的示例解决方案后,请务必立即按照以下步骤操作:

    1. 右键单击“解决方案资源管理器”最上面的解决方案节点,再选择“设置启动项目”
    2. 确保三个项目都在“操作”列中设置为“启动”
  2. 在“解决方案资源管理器”中,右键单击“ChainStore”项目,再依次选择“添加”>“新项”

  3. 在“添加新项”对话框中,选择“功能区自定义操作”,将它命名为“AddEmployeeToCorpDB”,再选择“添加”

  4. 打开的对话框会询问三个问题。 提供以下答案:

    问题 应给出的答案:
    想要在哪里公开自定义操作? 主机 Web
    自定义操作的作用范围是什么? 列表实例
    自定义操作的作用范围限定到了哪个特定项? 本地员工
  5. 选择“下一步”。此时,将会看到另外三个问题:

    问题 应给出的答案:
    控件位于何处? Ribbon.ListItem.Actions
    按钮控件的标签文本是什么? 添加到公司数据库
    单击按钮控件后转到何处? ChainStoreWeb\Pages\EmployeeAdder.aspx
    (在此页面中,代码隐藏会将员工添加到数据库)
  6. 单击“完成”

    此时,定义自定义操作的 elements.xml 文件添加到项目并打开。 多半可以将此文件视为黑匣。在阅读本系列后面的文章前,无需进行任何更改。 现在,只需注意以下几点:

    • CommandUIDefinition 元素的 Location 属性的值为 Ribbon.ListItem.Actions.Controls_children。 此值的第二部分 ListItem 确定了要将按钮添加到哪个功能区选项卡(但可能并不是选项卡的确切显示名称)。 此值的第三部分 Actions 确定了要将按钮添加到的功能区部分名称。
    • CommandUIHandler 元素的 CommandAction 属性以占位符 ~remoteAppUrl 开头。 占位符将在部署按钮时被替换为远程 Web 应用程序的 URL。
    • 向“CommandAction”值添加了几个查询参数,其中用大括号“{}”括住的值为占位符值。 这些占位符在运行时得到解析。 请注意,其中一个是用户在选择功能区自定义按钮前选择的列表项的 ID。
  7. 在“ChainStoreWeb”项目中,打开“Pages/EmployeeAdder.aspx”文件。 请注意,其中没有任何 UI。 加载项将使用此页面作为一种 Web 服务。 这是可能的,因为 ASP.NET System.Web.UI.Page 类实现 System.Web.IHttpHandler ,并且 Page_Load 事件在请求页面时自动运行。

  8. 打开代码隐藏文件“Pages/EmployeeAdder.aspx.cs”。 其中已有将员工添加到远程数据库的方法 AddLocalEmployeeToCorpDB。 它使用 SharePointContext 对象获取加载项用作租户鉴别器的主机 Web URL。 Page_Load 方法首先需要初始化此对象。 因为此对象是在加载项的起始页加载时在会话中进行创建和缓存,所以请将下面的代码添加到“Page_Load”方法中。 (SharePointContext 对象在 SharePointContext.cs 文件中进行定义,这个文件是由 Visual Studio 的 Office 开发人员工具在加载项解决方案创建时生成。)

    spContext = Session["SPContext"] as SharePointContext;
    
  9. 由于 AddLocalEmployeeToCorpDB 方法需要使用员工姓名作为参数,因此请将以下代码行添加到“Page_Load”方法中。 将在后续步骤中创建 GetLocalEmployeeName 方法。

    // Read from SharePoint 
    string employeeName = GetLocalEmployeeName();
    
  10. 在此代码行下面,添加对 AddLocalEmployeeToCorpDB 方法的调用。

    // Write to remote database 
    AddLocalEmployeeToCorpDB(employeeName);
    
  11. using 语句添加到命名空间 Microsoft.SharePoint.Client 的文件中。 (在“ChainStoreWeb”项目创建时,Visual Studio 的 Office 开发人员工具就在此项目中添加了 Microsoft.SharePoint.Client 程序集。)

  12. 现在,将下列方法添加到 EmployeeAdder 类。 MSDN 上的其他文章详细介绍了 SharePoint.NET 客户端对象模型 (CSOM),建议在完成本系列文章时探究此模型。 在本文中,请注意,ListItem 类表示 SharePoint 列表项,并且项中的字段值可通过“indexer”语法进行引用。 另请注意,代码将字段引用为“Title”,即使已将字段名称更改为“姓名”,也不例外。 这是因为代码始终按内部名称(而不是显示名称)引用字段。 字段的内部名称在字段创建时就已设置,并且永不改变。 将在后续步骤中完成 TODO1

    private string GetLocalEmployeeName()
    {
      ListItem localEmployee;
    
      // TODO1: Initialize the localEmployee object by getting  
      // the item from SharePoint.
    
      return localEmployee["Title"].ToString();
    }
    
  13. 代码需要使用列表项 ID,才能从 SharePoint 检索列表项。 将以下声明添加到 spContext 对象声明正下方的 EmployeeAdder 类中。

    private int listItemID;
    
  14. 现在,将下面的方法添加到 EmployeeAdder 类中,以从查询参数中获取列表项 ID。

    private int GetListItemIDFromQueryParameter()
    {
      int result;
      Int32.TryParse(Request.QueryString["SPListItemId"], out result);
      return result;
    }
    
  15. 若要初始化 listItemID 变量,请将以下代码行添加到初始化 spContext 变量的代码行正下方的 Page_Load 方法中。

    listItemID = GetListItemIDFromQueryParameter();
    
  16. GetLocalEmployeeName 中,将 TODO1 替换为以下代码。 目前,只需将此代码视为黑匣,尽管我们关注的是如何让自定义按钮正常运行。 本系列的下一篇文章将详细介绍此代码,即对 SharePoint 客户端对象模型的全面介绍。

    using (var clientContext = spContext.CreateUserClientContextForSPHost())
    {
      List localEmployeesList = clientContext.Web.Lists.GetByTitle("Local Employees");
      localEmployee = localEmployeesList.GetItemById(listItemID);
      clientContext.Load(localEmployee);
      clientContext.ExecuteQuery();
    }
    
    

    此时,整个方法应如下所示。

    private string GetLocalEmployeeName()
    {
      ListItem localEmployee;
    
      using (var clientContext = spContext.CreateUserClientContextForSPHost())
      {
        List localEmployeesList = clientContext.Web.Lists.GetByTitle("Local Employees");
        selectedLocalEmployee = localEmployeesList.GetItemById(listItemID);
        clientContext.Load(selectedLocalEmployee);
        clientContext.ExecuteQuery();
      }
      return localEmployee["Title"].ToString();
    }
    
  17. 由于 EmployeeAdder 页面其实不得予以呈现,因此请将以下代码添加到“Page_Load”方法中,作为最后一行代码。 这会将浏览器重定向回“本地员工”列表的列表视图页面。

    // Go back to the Local Employees page
    Response.Redirect(spContext.SPHostUrl.ToString() + "Lists/Local%20Employees/AllItems.aspx", true);
    

    此时,整个 Page_Load 方法应如下所示:

    protected void Page_Load(object sender, EventArgs e)
    {
      spContext = Session["SPContext"] as SharePointContext;
      listItemID = GetListItemIDFromQueryParameter();
    
      // Read from SharePoint
      string employeeName = GetLocalEmployeeName();
    
      // Write to remote database
      AddLocalEmployeeToCorpDB(employeeName);
    
      // Go back to the preceding page
      Response.Redirect(spContext.SPHostUrl.ToString() + "Lists/Local%20Employees/AllItems.aspx", true);
    }
    

请求获取对主机 Web 列表的读取权限

大家已发现,SharePoint 会在加载项安装时提示向加载项授予对主机 Web 的权限。 每次按 F5 都会重新安装加载项。 到目前为止,加载项只有所需的最少权限,但 GetLocalEmployeeName 方法需要有权读取主机网站的列表。 加载项使用加载项清单来指示 SharePoint 它需要哪些权限。 请按照以下步骤操作。

  1. 在“解决方案资源管理器”中,打开“ChainStore”项目中的 AppManifest.xml 文件(此文件名之所以为 AppManifest 是因为加载项过去常常称为“应用”)。 此时,清单设计器打开。

  2. 打开“权限”选项卡,选择“范围”列下方的空单元格,再从下拉列表中选择“列表”

  3. 在“权限”字段中,选择下拉列表中的“读取”

  4. 保持“属性”字段为空,并保存文件。 此时,“权限”选项卡应如下所示。

    图 2. “权限”选项卡

    加载项清单设计器的“权限”选项卡,其中“范围”列的值为“列表”,“权限”列的值为“读取”。

运行加载项并测试按钮

  1. 按 F5 键部署并运行加载项。 Visual Studio 在 IIS Express 中托管远程 Web 应用,并在 SQL Express 中托管 SQL 数据库。 此外,它还在测试 SharePoint 网站上临时安装并立即运行加载项。 在加载项的起始页打开前,将会看到向加载项授予权限的提示。 这次提示中有一个下拉列表,可以在其中选择应用需要读取的列表,如以下屏幕截图所示。

    图 3. SharePoint 外接程序权限提示

    SharePoint 加载项权限提示,在标记为“允许读取以下列表中的项”的下拉列表中,选择名为“本地员工”的列表

  2. 从列表中选择“本地员工”,再选择“信任它”

  3. 在加载项的起始页打开后,选择最上面部件版式控制中的“返回到网站”

  4. 在网站主页中,依次转到“网站内容”>“本地员工”。 此时,列表视图页面打开。

  5. 向列表添加几名员工。 不要选中“添加到企业 DB”复选框。

  6. 在功能区上,打开“项”选项卡。选项卡的“操作”部分中包含自定义按钮“添加到企业 DB”

  7. 选择列表项。 此时,页面和功能区应如下所示。

    图 4. 本地员工列表

    “本地员工”列表。突出显示了一项。上方是功能区,“操作”部分中有一个名为“添加到公司数据库”的按钮。

  8. 选择列表项后,选择“添加到企业 DB”

  9. 此时,页面似乎会重新加载,这是因为 EmployeeAdder 页面的 Page_Load 方法会重定向回这个页面。

  10. 使用浏览器的“后退”按钮两次,返回到加载项的起始页。

  11. 选择“显示员工”,此时员工列表中会填充所添加的员工。 具体应如下所示:

    图 5. 加载项起始页上的公司员工列表

    外接程序起始页上的公司员工列表,其中显示在之前步骤中选择的同一员工。

  12. 若要结束调试会话,请关闭浏览器窗口或停止在 Visual Studio 中进行调试。 每次按 F5,Visual Studio 都会撤回旧版加载项并安装最新版本。

  13. 将在其他文章中使用此加载项和 Visual Studio 解决方案,因此最好在使用一段时间后,再最后撤回一次加载项。 在“解决方案资源管理器”中,右键单击此项目,再选择“撤回”

后续步骤

下一篇文章将暂别编码,改为简要概述 SharePoint 客户端对象模型