向提供程序托管的加载项添加 SharePoint 写入操作

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

备注

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

本文将回归编码,介绍如何添加一些函数,用于将数据写入连锁店 SharePoint 加载项。

更改 SharePoint 列表项的列值

我们的外接程序具有一个自定义功能区按钮,可将员工从香港分店的“本地员工”列表添加到公司数据库。但是用户务必将“已添加到公司数据库”字段的值手动更改为 Yes。现在我们来添加代码以自动执行此操作。

备注

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

  1. 右键单击“解决方案资源管理器”最上面的解决方案节点,再选择“设置启动项目”。
  2. 确保三个项目都在“操作”列中设置为“启动”。
  1. "解决方案资源管理器"中,打开 EmployeeAdder.aspx.cs 文件。

  2. 将以下代码行添加到“Page_Load”方法中,位置为 AddLocalEmployeeToCorpDB 调用和 Response.Redirect 调用之间。 将在下一步中创建 SetLocalEmployeeSyncStatus 方法。

       // Write to SharePoint
     SetLocalEmployeeSyncStatus();
    
  3. 将下列新方法添加到 EmployeeAdder 类。

       private void SetLocalEmployeeSyncStatus()
     {
         using (var clientContext = spContext.CreateUserClientContextForSPHost())
         {
             List localEmployeesList = clientContext.Web.Lists.GetByTitle("Local Employees");
             ListItem selectedLocalEmployee = localEmployeesList.GetItemById(listItemID);
             selectedLocalEmployee["Added_x0020_to_x0020_Corporate_x"] = true;
             selectedLocalEmployee.Update();
             clientContext.ExecuteQuery();
         }
     }
    

    关于此代码,请注意以下几点:

    • The internal name for the Added to Corporate DB field is odd-looking. Internal field names cannot contain spaces, so when a user creates a field with spaces in its display name, SharePoint substitutes the string "x0020" for each space when it sets the internal name. This turns "Added to Employee DB" into "Added_x0020_to_x0020_Corporate_x0020_DB". Internal names cannot be more than 32 characters, so the name is truncated to just "Added_x0020_to_x0020_Corporate_x".
    • 尽管“添加到企业 DB”列在 SharePoint UI 中是“是/否”字段,但其实它就是一个布尔字段,因此它的值设置为“true”,而不是“Yes”。
    • 必须调用 ListItem 类的 Update 方法,将更改提交到 SharePoint 的内容数据库。这是一个一般原则,但并不是十分普遍,当您更改存储在 SharePoint 数据库中的对象的属性值时,您必须调用对象的 Update 方法。

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

由于加载项现在要对列表执行写入和读取操作,因此需要将加载项请求获取的权限从“读取”提升到“写入”。 请按照以下步骤操作。

  1. 在“解决方案资源管理器”中,打开“ChainStore”项目中的 AppManifest.xml 文件。
  2. 打开“权限”选项卡。在“权限”字段中,从下拉列表中选择“写入”。
  3. 保存文件。

运行加载项并测试按钮

  1. 使用 F5 键部署并运行您的外接程序。Visual Studio 在 IIS Express 中托管远程 Web 应用程序,在 SQL Express 中托管 SQL 数据库。它还会在 SharePoint 测试网站上临时安装外接程序并立即运行它。在起始页打开之前,将提示您向外接程序授予权限。

  2. 在权限表单上,从列表中选择“本地员工”,再选择“信任它”。

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

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

  5. 如果列表中没有用户在“添加到企业 DB”列中的值为“否”,请向列表添加一个员工,但 不要选中“添加到企业 DB”复选框。

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

  7. 在列表中选择“添加到企业 DB”列值为“否”的员工。

  8. 选择“添加到企业 DB”按钮。 (必须先选择一项。)

  9. 此时,页面似乎会重新加载,这是因为 EmployeeAdder 页面的 Page_Load 方法会重定向回这个页面。 员工对应的“添加到企业 DB”字段值会变成“是”。

    备注

    如何防止用户手动更改“已添加到公司数据库”的值而导致列表和公司数据库不一致?目前尚无解决办法。您可在本系列的后续文章中获取此问题的解决方案。

1.To 结束调试会话,请关闭浏览器窗口或停止调试Visual Studio。 每次按 F5,Visual Studio 都会撤回旧版加载项并安装最新版本。 1.右键单击"解决方案资源管理器 "中的项目, 然后选择"撤回 "。

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

对连锁店加载项的下一项改进是在列表中新建项,而不是仅仅更改现有项中的字段。 具体来说,在公司一级下达新订单时,便会在 SharePoint 列表中自动创建一项,以提醒本地员工一段时间后应到货。 此列表称为“按预期到货”,具体创建步骤如下。 本系列后面的一篇文章将介绍如何以编程方式向主机网站添加自定义列表,但本文暂介绍如何手动添加此列表。

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

  2. 在“添加自定义列表”对话框中,指定“按预期到货”作为名称,再选择“创建”。

  3. 在“网站内容”页上,打开“按预期到货”列表。

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

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

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

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

  8. 在本系列的前一篇文章中,您学习了如何为列表创建自定义列。对于"预期装运"列表,使用下表中的值添加四个列。将所有其他设置保留为默认值。

    列名称 类型 是否必需? 默认值
    供应商 单行文本 可选
    数量 编号 必需 1
    已送达 是/否 可选
    已添加到库存 是/否 可选
  9. 在“列表设置”页上创建列后,选择“网站内容”打开“网站内容”页。 打开“按预期到货”列表。

  10. 选择“新建项”。 项创建表单应完全如下所示,包括两个表示必填字段的星号。

    图 1:“按预期到货”列表的项创建表单

    “预期装运”列表的项目创建窗体,包含“产品”、“供应商”、“数量”、“已到达”和“已添加到库存”字段。按“产品”和“数量”的标题星号,“数量”的默认值为 1。

  11. 由于并不要在此列表中手动创建项,因此请单击“取消”。

将项插入 SharePoint 列表

现在您向外接程序添加了一个函数,可在公司级别为香港分店下达订单时在"预期装运"列表中创建一个项目。

  1. 在"解决方案资源管理器"中,打开 OrderForm.aspx.cs 文件。

  2. 将“Microsoft.SharePoint.Client”的“using”语句添加到文件最上面。

  3. 将以下代码行添加到“btnCreateOrder_Click”方法中,位置为 CreateOrder 调用正下方。 将在下一步中创建 CreateExpectedShipment 方法。

      CreateExpectedShipment(txtBoxSupplier.Text, txtBoxItemName.Text, quantity);
    
  4. 将下列方法添加到 OrderForm 类。

    private void CreateExpectedShipment(string supplier, string product, UInt16 quantity)
    {
      using (var clientContext = spContext.CreateUserClientContextForSPHost())
      {
        List expectedShipmentsList = clientContext.Web.Lists.GetByTitle("Expected Shipments");
        ListItemCreationInformation itemCreateInfo = new ListItemCreationInformation();
        ListItem newItem = expectedShipmentsList.AddItem(itemCreateInfo);
        newItem["Title"] = product;
        newItem["Supplier"] = supplier;
        newItem["Quantity"] = quantity;
        newItem.Update();
        clientContext.ExecuteQuery();
      }
    }
    

    关于此代码,请注意以下几点:

    • ListItem 对象并不是使用构造函数创建而成。 这是出于提升性能的考虑。 ListItem 对象有许多属性(采用默认值)。 如果使用构造函数,整个对象都会被添加到 ExecuteQuery 方法发送给服务器的 XML 消息中。
    • ListItemCreationInformation 是轻型对象,只包含服务器创建 ListItem 对象至少所需的非默认值。 虽然似乎是有一行代码负责创建 ListItem 对象,但回顾一下便知,此代码行只向发送给服务器的消息添加一些 XML 标记。 ListItem 对象是在服务器上进行创建。
    • 无需将 ListItem 对象向下重新引入客户端,因此没有 ClientContext.Load 方法调用。
    • 此代码无需显式设置“到货”或“添加到库存”字段,因为它们的默认值“否”就是所需的值。

检查组件是否已遭删除

具有 SharePoint 列表的所有者权限的用户均可删除列表。如果外接程序将列表部署到主机 Web,主机 Web 的网站所有者即可将其删除。如果所有者决定在不使用列表提供的功能的情况下将其删除,可能会出现这种情况。(如果所有者改变主意,可从 SharePoint 回收站中将其还原。)

CreateExpectedShipment 方法的执行取决于是否有“按预期到货”列表。 假设网站所有者已决定删除此列表。 稍后,如果有订单通过加载项的“订单表单”进行添加,则会调用 CreateExpectedShipment 方法,并抛出异常消息,提示 SharePoint 网站上没有“按预期到货”列表。

建议此方法先检查 expectedShipmentsList 是否为 NULL,再对它执行其他任何操作。 如果使用 CSOM,无法 通过下面这样简单的结构执行此检查:

if (expectedShipmentsList != null) { ... }

相反,需要使用名为 ConditionalScope 的特殊 CSOM 类。 造成这种情况的原因与 CSOM 的批量系统有关,本系列中的上一篇文章提到过此系统(请参阅客户端运行时和批处理)。 ConditionalScope 和批量系统是高级主题,并不在本入门系列文章的介绍范围之内。不过,应在完成本系列教程后,参阅与它们相关的 MSDN 文档。

检查是否有列表的备用方法如下:可以使用下面的代码,检查网站列举的列表中是否包含具有指定名称的列表,而无需使用 GetByTitle 方法获取对列表的引用。

var query = from list in clientContext.Web.Lists 
             where list.Title == "Expected Shipments" 
             select list; 
IEnumerable<List> matchingLists = clientContext.LoadQuery(query); 
clientContext.ExecuteQuery(); 
if (matchingLists.Count() != 0) 
{ 
  List expectedShipmentsList = matchingLists.Single(); 
  // Do something with the list. 
}
clientContext.ExecuteQuery(); 

上面的代码可以避免 ConditionalScope 类的复杂使用步骤,本系列文章的其他地方也正是使用了此代码。 不过,也有一个缺点,即此代码需要单独额外调用 ExecuteQuery,才能获取要在 if 语句中检查的值。

如果在“CreateExpectedShipment”方法中使用这项技术来检查是否有此列表,这种方法需要调用 ExecuteQuery 两次,每次调用都会从远程 Web 服务器向 SharePoint 发送 HTTP 请求。 由于这些请求是任何 CSOM 方法中最耗时的部分,因此最佳做法通常是最大限度地减小这些请求。

将按原样使用 CreateExpectedShipment 方法,但在生产加载项中,需要考虑如何才能在检测到所引用的组件已遭删除时继续使用代码。 一种方法是以编程方式从回收站还原列表,但这种方法会令有意删除列表的用户生厌。

此外,另请注意,不执行任何操作来阻止异常抛出可能是最佳选择。SharePoint 中的异常会提醒用户,列表的删除已对加载项造成部分损坏,而删除列表的人员可能还没有意识到这一点。然后,用户可以决定是要从回收站中还原列表,还是任凭此部分加载项功能无法再正常运行下去。

请求获取网站管理权限

回顾一下,当加载项请求获取列表范围内读取或写入权限时,SharePoint 会提示用户信任加载项,并在对话框中提供下拉列表,以供用户选择加载项应有权访问的列表。 只能选择一个列表。 但现在,连锁店加载项对两个不同的列表执行写入操作。 若要获取对多个列表的访问权限,加载项必须请求获取 Web 范围内权限。 请按照以下步骤操作:

  1. 在“解决方案资源管理器”中,打开“ChainStore”项目中的 AppManifest.xml 文件。
  2. 打开“权限”选项卡。在“范围”字段中,从下拉列表中选择“Web”。
  3. 在“权限”字段中,从下拉列表中选择“写入”。
  4. 保存文件。

运行加载项并测试项创建

  1. 使用 F5 键部署并运行您的外接程序。Visual Studio 在 IIS Express 中托管远程 Web 应用程序,在 SQL Express 中托管 SQL 数据库。它还会在 SharePoint 测试网站上临时安装外接程序并立即运行它。在起始页打开之前,将提示您向外接程序授予权限。

  2. 在加载项的起始页打开后,选择页面底部的“订单表单”链接。

  3. 在表单中输入一些值,再选择“下订单”。

  4. 使用浏览器的“后退”按钮返回到起始页,再选择最上面部件版式控制中的“返回到网站”。

  5. 在香港店的主页中,转到“网站内容”,再打开“按预期到货”列表。 此时,列表上有一项与订单对应。 例如,下面的屏幕截图。

    图 2:包含一个项的“按预期到货”列表

    包含一个项的“按预期到货”列表。 “产品”和“供应商”字段中有名称。 “数量”字段中有数字。 两个“是/否”字段均设置为“否”。

  6. 若要结束调试会话,请关闭浏览器窗口或停止在 Visual Studio 中进行调试。每次按 F5,Visual Studio 都会取消旧版外接程序并安装最新版本。

  7. 在“解决方案资源管理器”中,右键单击此项目,再选择“撤回”。

后续步骤

下一篇文章在提供程序托管的加载项中添加加载项部件将介绍如何在 SharePoint 页面上以 Web 部件形式呈现远程订单表单。