为 SharePoint 加载项中的更新事件创建处理程序

开始前,需要十分熟悉处理加载项事件更新 SharePoint 加载项,以及其中列出的先决条件和核心概念。

注意

版本号系统: 为保持一致性,本主题假定加载项版本号为 1.0.0.0、2.0.0.0、3.0.0.0 等。 但是,无论您的编号系统是什么,逻辑和指南都适用。

创建 UpgradedEventEndpoint 接收器

对于自定义更新逻辑,可以创建 SharePoint 远程事件接收器,用于处理加载项更新事件。 请慎用此技术。 只有在更新步骤无法通过其他任何方式完成时,才使用此技术。 此外,处理加载项事件中的指南还适用于加载项更新事件,与加载项安装事件和加载项卸载事件一样。 这包括:

  • 处理程序必须在 30 秒内完成,并向 SharePoint 返回取消或继续状态。 如果未返回,SharePoint 最多可再重新调用此处理程序三次。

  • 如果处理程序返回取消状态,那么 SharePoint 最多再会重试三次。

  • 您通常需要将回滚和"已完成"逻辑包含在您的处理程序中。

UpgradedEventEndpoint 处理程序有用的一种情况是当将计算字段添加到远程数据库的情况。 假设添加了一个"城市"列,并且其值从现有的"邮政编码"列计算得出。 UpgradedEventEndpoint 处理程序中的代码可以循环访问数据库中的现有项目,并根据"邮政编码"字段的值和某些将邮政编码映射到城市的外部数据源为新的"城市"字段填写值。 数据库架构本身的更改最好通过使用数据库平台的最佳实践在 UpgradedEventEndpoint 处理程序外部实现。

若要详细了解如何创建加载项事件处理程序,请参阅处理 SharePoint 加载项中的事件在 SharePoint 加载项中创建加载项事件接收器

若要执行以下过程,需要已将加载项事件接收器项添加到 Visual Studio 中的 SharePoint 加载项项目。

首次处理加载项更新事件的具体步骤

  1. 打开 AppEventReceiver.svc.cs 文件,并向 ProcessEvent 方法添加条件结构,测试调用处理程序的事件是否为更新事件。 此结构中包含更新代码。 如果您的代码需要访问 SharePoint,则可以使用 SharePoint 托管代码客户端对象模型 (CSOM) 或代表性状态传输 (REST) 接口。

    条件结构在方法中的位置取决于您在方法中结构化其他代码的方式。 它通常是测试安装的外接程序和外接程序卸载事件的类似条件结构的对应项。 它可能位于某个条件结构中(测试传递给 ProcessEventSPRemoteEventProperties 对象的某些属性或子属性是否为 null 值或其他无效值)。 也可能包含在 try 块中。

    下面是此结构的一个示例。 properties 对象是一个 SPRemoteEventProperties 对象。

       if (properties.EventType == SPRemoteEventType.AppUpgraded)
     {
     }
    
    
  2. 若要在处理程序中使用 CSOM,添加(在条件块内) using 块,该块会通过调用 TokenHelper.CreateAppEventClientContext 方法获取 ClientContext 对象。 为第二个参数指定 true,以访问外接程序 Web。 指定为 false 可以访问主机 Web。 如需同时访问这两者,必须使用两个不同的客户端上下文对象。

  3. 如果您的处理程序需要访问非 SharePoint 组件,则将该代码放到任何客户端上下文块之外。 您的代码的结构应该与以下结构类似:

       if (properties.EventType == SPRemoteEventType.AppUpgraded)
     {
         using (ClientContext cc = TokenHelper.CreateAppEventClientContext(properties, true))
         {
             // CSOM code that accesses the add-in web
         }
         using (ClientContext cc = TokenHelper.CreateAppEventClientContext(properties, false))
         {
             // CSOM code that accesses the host web
         }
         // Other update code
     }
    
    
  4. 若要使用 REST 界面,您的代码会使用 TokenHelper 类中的其他方法获取访问令牌,之后,该令牌会包含在向 SharePoint 发出的请求中。 有关详细信息,请参阅 使用 SharePoint REST 终结点完成基本操作。 您的代码的结构应该与以下结构类似。

       if (properties.EventType == SPRemoteEventType.AppUpgraded)
     {
         string contextTokenString = TokenHelper.GetContextTokenFromRequest(Request);
         if (contextTokenString != null)
         {
             contextToken = TokenHelper.ReadAndValidateContextToken(contextTokenString, 
                                                                                                                       Request.Url.Authority);
             accessToken = TokenHelper.GetAccessToken(contextToken, sharepointUrl.Authority)
                                        .AccessToken;
    
            // REST code that accesses SharePoint
         }  
         // Other update code
     }
    
    
  5. 若要访问 SharePoint,REST 代码还需要知道主机 Web 和/或加载项 Web 的 URL。 这些 URL 均是传递到 ProcessEvent 方法的 SPRemoteEventProperties 对象的子属性。 下面的代码展示了如何获取它们。

       Uri hostWebURL = properties.AppEventProperties.HostWebFullUrl;
       Uri appWebURL = properties.AppEventProperties.AppWebFullUrl;
    

第二次(或第三次等)更新外接程序时,可能需要确保某些更新逻辑不能在同一外接程序实例中运行多次。 以下过程显示了如何操作。

在随后更新时处理加载项更新事件的具体步骤

  1. 打开 AppEventReceiver.svc.cs 文件,查找从 1.0.0.0 开始的第一个更新 (中实现更新操作的代码。到 2.0.0.0) 。 将这称为“旧更新代码”。 (此代码通常位于获取客户端上下文或访问令牌的授权代码之后。) 现在,) 从 2.0.0.0 到 3.0.0.0 (再次更新, 此处的上一个更新代码中通常存在你不希望在同一外接程序实例上再次运行的操作,但你确实希望它在从未更新到 2.0.0.0 的外接程序实例上运行 (,在这种情况下, 实例现在一直从 1.0.0.0 更新。到 3.0.0.0) 。

  2. 将旧更新代码封装到具有以下用途的条件结构中:测试是否有旧版加载项实例,只有当结构中的代码尚未对此加载项实例运行过时,才会予以执行。 旧版实例存储在 SPRemoteEventProperties 对象的 PreviousVersion 子属性中。

  3. 在此结构下添加新的更新逻辑(用于从 2.0.0.0 更新到 3.0.0.0)。 示例如下。

       Version ver2OOO = new Version("2.0.0.0");
     if (properties.AppEventProperties.PreviousVersion < ver2OOO)
     {
         // Code to update from 1.0.0.0 to 2.0.0.0 (previous update code) is here.
     }
     // Code to update from 2.0.0.0 to 3.0.0.0 is here.
    
    
  4. 对于每次后续更新,重复上述步骤。 对于从 3.0.0.0 到 4.0.0.0 的更新,您的代码应该具有以下结构。

     Version ver2OOO = new Version("2.0.0.0");
     if (properties.AppEventProperties.PreviousVersion < ver2OOO)
     {
         // Code to update from 1.0.0.0 to 2.0.0.0 is here.
     }
    
     Version ver3OOO = new Version("3.0.0.0");
     if (properties.AppEventProperties.PreviousVersion < ver3OOO)
     {
         // Code to update from 2.0.0.0 to 3.0.0.0 (previous update code) is here.
     }
     // Code to update from 3.0.0.0 to 4.0.0.0 is here.
    
    

重要

如果在 UpgradedEventEndpoint 处理程序中向加载项添加组件,请务必将相同的代码添加到 InstalledEventEndpoint 处理程序中,因为也希望全新安装的加载项中包含此组件。 此外,还应添加 UninstallingEventEndpoint(或修改它),以便加载项可以删除此组件。

InstalledEventEndpoint 添加或更改的内容多半都应该可由 UninstallingEventEndpoint 反向处理或删除。 不适用此规则的一个例外情况是,不得删除从第二阶段回收站删除加载项后仍有用的数据。 (加载项创建的网站(而不是加载项 Web)应视为数据。)

向处理程序添加回滚逻辑

如果在加载项更新期间出错,SharePoint 基础结构会停止更新过程,并将加载项实例及其所有组件回滚到旧版加载项实例。 不过,基础结构无从得知 UpgradedEventEndpoint 处理程序逻辑执行的操作,因此有时可能无法撤消它。 未处理异常在 UpgradedEventEndpoint 处理程序执行时抛出,几乎可以肯定地指明应回滚整个加载项更新过程,但这并不是因为基础结构不知道如何撤消 UpgradedEventEndpoint 代码可能已执行的一些操作。 因此,UpgradedEventEndpoint 代码必须:

  • 捕获所有异常。

  • 生成自定义回滚代码分支,以撤消那一刻前已经执行的操作。

  • 向 SharePoint 基础结构发出信号,提醒应回滚整个加载项更新过程。

  • 将错误消息传递给基础架构。

并非 UpgradedEventEndpoint 执行的所有操作都需要在处理程序内明确撤销。 由于加载项 Web 将由基础结构进行回滚,因此代码无需撤消对加载项 Web 所做的更改。 不过,UpgradedEventEndpoint 处理程序通常确实要反向处理对主机 Web 或 SharePoint 加载项外部的其他组件所做的更改。

在第二次(或第三次等)更新中,您的异常处理逻辑必须考虑这样一个事实:正在更新的外接程序实例并不一定就是上一版本。 如果不是,可能会有两个或者更多更新代码块需要撤销。 因此,您需要基于之前版本号的条件逻辑。 以下是更新到版本 4.0.0.0 的回滚逻辑的一个示例。

catch (Exception e)
{ 
    // Rollback of the 3.0.0.0 to 4.0.0.0 update logic goes here.

    Version ver3OOO = new Version("3.0.0.0");
    if (properties.AppEventProperties.PreviousVersion < ver3OOO)
    {
        // Rollback of the 2.0.0.0 to 3.0.0.0 update logic goes here.
    }

    Version ver2OOO = new Version("2.0.0.0");
    if (properties.AppEventProperties.PreviousVersion < ver2OOO)
    {
        // Rollback of the 1.0.0.0 to 2.0.0.0 update logic goes here.
    }
}

错误处理的最后一步应是,向 ProcessEvent 方法返回给 SharePoint 更新基础结构的 SPRemoteEventResult 对象分配错误消息和取消状态。 示例如下。 在此代码中, result 是之前已在 ProcessEvent 方法中声明的 SPRemoteEventResult 对象。

catch (Exception e)
{     
    result.ErrorMessage = "custom message " + e.Message;
    result.Status = SPRemoteEventServiceStatus.CancelWithError;

     // Rollback logic from the preceding code snippet  is here. 

}

重要

请务必将 SPRemoteEventServiceStatus.CancelWithError(或 SPRemoteEventServiceStatus.CancelNoError)分配给 Status 属性。 此属性就是指示基础结构回滚更新过程的信号。 但在回滚更新之前,SharePoint 将重试三次您的处理程序。

使用处理程序委派策略

处理加载项事件中介绍的处理程序委派策略也可用于 UpdatedEventHandler。 不是只有回滚和“已完成”逻辑在远程组件上绑定并运行,版本控制逻辑也是如此。 此策略的限制也适用于这里;通常不能用它来更新多个远程系统。

后续步骤

请返回到更新加载项的主要步骤,或直接转到以下文章之一,了解如何更新 SharePoint 加载项的下一个主要组件。

另请参阅