How to: Save and Restore a Change Token

SharePoint 2010

Last modified: July 28, 2009

Applies to: SharePoint Foundation 2010

If your application queries the change log on a regular schedule, you might want to persist the last change token at the end of a run, and later reconstruct the persisted token to use as a starting point for the next run. To save a change token, first call the SPChangeToken.ToString() method to get a string representation of the token; then persist the result to permanent storage. To restore the token, retrieve the string from storage and pass it to the SPChangeToken.SPChangeToken(String) constructor.

Caution note Caution

Change tokens are specific to a list, Web site, site collection, or content database. The SPChangeToken object from one object cannot be used in the GetChanges method of another object. The only exception to this rule is that an SPChangeToken object from a SPContentDatabase object can be used in the GetChanges method for any object that is contained in that content database.

The following example is a console application that queries the change log for changes that have content database scope.

The first time the application runs, the query retrieves all changes recorded from the beginning of the log to its current end. This query is performed by first setting the ChangeTokenStart property of an SPChangeQuery object to a null value, and then passing the SPQuery object to the GetChanges method. After all changes have been processed, the program serializes the last change token from the last batch of changes by calling the ToString() method and stores the result in a file on disk.

On subsequent runs, the program deserializes the stored change token and uses it to set the ChangeTokenStart property, which defines the starting point for its query against the change log. The ChangeTokenEnd property is left at its default null value, which signals that the query should proceed to the end of the log.

The important work is done in the GetStartingToken function, which is where the SPChangeToken constructor is called.

using System;
using System.IO;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace Test
{
   class ConsoleApp
   {
      private const string DATA_FILE_PATH = "ChangeToken.dat";

      static void Main(string[] args)
      {
         using (SPSite site = new SPSite("http://localhost"))
         {
            SPChangeQuery query = new SPChangeQuery(true, true);
            query.ChangeTokenStart = GetStartingToken();

            while (true)
            {
               // Get a batch of changes.
               SPChangeCollection changes = site.ContentDatabase.GetChanges(query);

               // Process them.
               foreach (SPChange change in changes)
               {
                  Console.WriteLine("Date: {0}  Type of object: {1}  Type of change: {2}",
                     change.Time.ToShortDateString(), change.GetType().ToString(), change.ChangeType);
               }

               // Starting point for next batch.
               query.ChangeTokenStart = changes.LastChangeToken;

               // If this is the last batch, exit.
               if (changes.Count < query.FetchLimit)
                  break;
            }
            // Serialize the last token as a starting point for the next run.
            SaveLastToken(query.ChangeTokenStart);
         }

         Console.Write("\nPress ENTER to continue...");
         Console.ReadLine();
      }

      static SPChangeToken GetStartingToken()
      {
         // Passing a null token to GetChanges fetches 
         // changes from the start of the log.
         SPChangeToken token = null;

         // If we have a token from the last run, use it.
         if (File.Exists(DATA_FILE_PATH))
         {
            using (FileStream fs = File.OpenRead(DATA_FILE_PATH))
            {
               BinaryReader br = new BinaryReader(fs);
               try
               {
                  string str = br.ReadString();
                  // Construct a change token from serialized string.
                  token = new SPChangeToken(str);
               }
               catch (EndOfStreamException e)
               {
                  // No serialized string, so do nothing.
               }
               finally
               {
                  br.Close();
               }
            }
         }
         return token;
      }

      static void SaveLastToken(SPChangeToken token)
      {
         using (FileStream fs = File.Create(DATA_FILE_PATH))
         {
            // Serialize the token.
            BinaryWriter bw = new BinaryWriter(fs);
            string s = token.ToString();
            bw.Write(s);

            // Flush and close.
            bw.Flush();
            bw.Close();
         }
      }
   }
}
Show: