使用 ChangeQuery 和 ChangeToken 查询 SharePoint 更改日志

使用 ChangeQueryChangeToken 在 SharePoint 更改日志中查询对 SharePoint 内容数据库、网站集、网站或列表所做的更改。

适用于:SharePoint 2013 | SharePoint 外接程序 | SharePoint Online

可以使用 ChangeQueryChangeToken 查询 SharePoint 更改日志,以便查找和处理 SharePoint 内容数据库、网站集、网站或列表的更改。

Core.ListItemChangeMonitor 代码示例展示了如何使用 SharePoint 更改日志,查找和处理 SharePoint 列表更改。 此代码示例可用于:

  • 监视 SharePoint,以便获取列表、网站、网站集或内容数据库的更改。

  • 在列表项有变化后,启动业务流程。

  • 补充远程事件接收器。 结合使用更改日志模式与远程事件接收器模式,可以提高体系结构的可靠性,更好地处理 SharePoint 内容数据库、网站集、网站或列表的所有更改。 虽然远程事件接收器会立即运行,但由于它们是在远程服务器上运行,因此可能会遇到通信故障。 更改日志模式确保所有更改都可供处理,但处理更改的应用(例如,计时器作业)通常是定期运行。 也就是说,不会立即处理更改。 如果结合使用这两种模式,请确保使用一种机制,以防处理同一更改两次。 有关详细信息,请参阅在 SharePoint 中使用远程事件接收器

准备工作

若要开始,请从 GitHub 上的 Office 365 开发人员模式和做法(#office-365-开发人员模式和做法) 项目下载 Core.ListItemChangeMonitor(#core.listitemchangemonitor) 示例外接程序。

在运行此代码示例之前,请执行以下操作:

  1. 登录到你想要创建列表的 Office 365 网站。

  2. 选择“网站内容”

  3. 选择“添加外接程序”

  4. 选择“自定义列表”

  5. 在“名称”中输入 TestList

  6. 选择“创建”

若要查看此代码示例的演示,请执行以下步骤:

  1. 选择“在 Visual Studio 中 启动 ”。

  2. 输入 Office 365 网站 URL、列表名称 (TestList) 和 Office 365 凭据。 控制台应用现在等待“TestList”发生变化。 默认情况下,控制台应用程序将检查更改日志并每隔 30 秒更新显示。

  3. 将新项目添加到“TestList”

    1. 打开Office 365网站并转到“网站内容>测试列表”。

    2. 单击“新建项目”

    3. 在“标题”中输入 MyTitle,然后选择“保存”

  4. 验证所做的更改是否显示在控制台应用中。 可以通过在控制台应用程序中输入 r 来强制控制台应用程序读取 SharePoint 的更改日志。

使用 Core.ListItemChangeMonitor 加载项

在 Program.cs 中,Main 调用 DoWork 来读取和处理 SharePoint 的更改日志:

  1. 创建 ChangeQuery 对象以访问 SharePoint 的更改日志。

  2. 通过 cq.Item = true,使用更改日志返回对项目的更改。 这些更改包括:

    • 使用 cq.Add= true 添加的新项目。

    • 使用 cq 删除了项 。DeleteObject = true

    • 使用 cq.Update=true 修改的项目。

  3. 创建 ChangeToken 对象来从某个时间点的更改日志中读取更改。

  4. ChangeToken.StringValue(#changetoken.stringvalue) 设置版本号、更改范围、TestList 的 GUID,更改发生的日期和时间以及 ChangeToken (使用值 -1 初始化) 上的更改项值。 此代码示例使用 DateTime.Now.AddDays(-2).ToUniversalTime().Ticks.ToString() 将更改发生日期和时间初始化为前 2 天,限制从更改日志中读取的更改量。

  5. 更改日志每 30 秒(由常量 WaitSeconds 设置的默认等待时间)读取一次,或者在用户输入“r”时读取。 读取更改日志时,控制台应用执行以下步骤:

    1. 使用 List.GetChanges 返回 ChangeCollection,其中包含一组自上次处理更改后发生的列表更改。

    2. 调用 DisplayChanges 以显示 ChangeCollection 对象中的更改。

    3. 设置从更改日志中读取更改的新时间点。 如果对列表进行了更改(在 coll 中返回),则将 ChangeTokenStart 设置为上次更改的日期和时间。

注意

本文中的代码按原样提供,不提供任何明示或暗示的担保,包括对特定用途适用性、适销性或不侵权的默示担保。

private static void DoWork()
        {
            Console.WriteLine();
            Console.WriteLine("Url: " + url);
            Console.WriteLine("User name: " + userName);
            Console.WriteLine("List name: " + listName);
            Console.WriteLine();
            try
            {

                Console.WriteLine(string.Format("Connecting to {0}", url));
                Console.WriteLine();
                ClientContext cc = new ClientContext(url);
                cc.AuthenticationMode = ClientAuthenticationMode.Default;
                cc.Credentials = new SharePointOnlineCredentials(userName, password);

                ListCollection lists = cc.Web.Lists;
                IEnumerable<List> results = cc.LoadQuery<List>(lists.Where(lst => lst.Title == listName));
                cc.ExecuteQuery();
                List list = results.FirstOrDefault();
                if (list == null)
                {

                    Console.WriteLine("A list named \"{0}\" does not exist. Press any key to exit...", listName);
                    Console.ReadKey();
                    return;
                }

                nextRunTime = DateTime.Now;

                ChangeQuery cq = new ChangeQuery(false, false);
                cq.Item = true;
                cq.DeleteObject = true;
                cq.Add = true;
                cq.Update = true;

                // Set the ChangeTokenStart to two days ago to reduce how much data is returned from the change log. Depending on your requirements, you might want to change this value. 
                // The value of the string assigned to ChangeTokenStart.StringValue is semicolon delimited, and takes the following parameters in the order listed:
                // Version number. 
                // The change scope (0 - Content Database, 1 - site collection, 2 - site, 3 - list).
                // GUID of the item the scope applies to (for example, GUID of the list). 
                // Time (in UTC) from when changes occurred.
                // Initialize the change item on the ChangeToken using a default value of -1.

                cq.ChangeTokenStart = new ChangeToken();
                cq.ChangeTokenStart.StringValue = string.Format("1;3;{0};{1};-1", list.Id.ToString(), DateTime.Now.AddDays(-2).ToUniversalTime().Ticks.ToString());

                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(string.Format("Ctrl+c to exit. Press \"r\" key to force the console application to read the change log without waiting {0} seconds.", WaitSeconds));
                Console.WriteLine();
                Console.ResetColor();
                do
                {
                    do
                    {
                        if (Console.KeyAvailable &amp;&amp; Console.ReadKey(true).KeyChar == 'r') { break; }
                    }
                    while (nextRunTime > DateTime.Now);

                    Console.WriteLine(string.Format("Looking for items modified after {0} UTC", GetDateStringFromChangeToken(cq.ChangeTokenStart)));

                    
                    ChangeCollection coll = list.GetChanges(cq);
                    cc.Load(coll);
                    cc.ExecuteQuery();


                    DisplayChanges(coll, cq.ChangeTokenStart);
                    // If there are changes to the list (which was returned in coll), set ChangeTokenStart to the last change's date and time. This will be used as the starting point for the next read from the change log.                      
                    cq.ChangeTokenStart = coll.Count > 0 ? coll.Last().ChangeToken : cq.ChangeTokenStart;

                    nextRunTime = DateTime.Now.AddSeconds(WaitSeconds);

                } while (true);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                Console.WriteLine("Press any key to exit...");
                Console.ReadKey();

            }
        }

另请参阅