SPChangeTokenCollection Class
Represents a collection of SPChangeToken objects.
Inheritance Hierarchy
System.Object
Microsoft.SharePoint.Administration.SPAutoSerializingObject
Microsoft.SharePoint.SPBaseCollection
Microsoft.SharePoint.SPChangeTokenCollection
Namespace: Microsoft.SharePoint
Assembly: Microsoft.SharePoint (in Microsoft.SharePoint.dll)
Available in Sandboxed Solutions: Yes
Available in SharePoint Online
Syntax
'Declaration
<SubsetCallableTypeAttribute> _
Public NotInheritable Class SPChangeTokenCollection _
Inherits SPBaseCollection
'Usage
Dim instance As SPChangeTokenCollection
[SubsetCallableTypeAttribute]
public sealed class SPChangeTokenCollection : SPBaseCollection
Remarks
This collection is provided so that you can easily manage change logs at the Web application level. Each content database in a Web application maintains its own change log. If you want a consolidated change report for multiple content databases, you can use an SPChangeTokenCollection object to store change tokens for all databases in a single collection. Once you have a collection of change tokens, you can enumerate the collection and ask each database in turn for its changes by calling the GetChanges(SPChangeToken) method. You can also serialize a collection using the ToString() method, and store it on disk. Later, when you want to revisit the change logs, you can reconstruct the collection using a variation of the constructor that accepts a string argument, and then use the deserialized change token collection to query the change logs again.
Examples
The following example is a console application that queries the change log for each content database in a Web application. On the program’s first run, all changes are retrieved from each log. After processing each collection of changes, the program saves the last change token in the change collection to an SPChangeTokenCollection collection. When all logs have been processed, the SPChangeTokenCollection object is serialized, and the resulting string is stored in a file on disk.
On subsequent runs of the program, the data file is read, the string representation of the collection is retrieved, and the SPChangeTokenCollection object is reconstructed. The change tokens in the collection are then used to fetch changes made since the last run of the program.
This example makes no attempt to save the information that it retrieves from the change logs. It simply prints the output to the console. A useful enhancement would be to add code for consolidating changes in a file or database, where they could be subjected to further analysis.
using System;
using System.IO;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
namespace Test
{
class ConsoleApp
{
private const string DATA_FILE_PATH = "ChangeTokens.dat";
static void Main(string[] args)
{
// Get a collection of content databases
SPWebApplication wa = SPWebApplication.Lookup(new Uri("https://localhost"));
SPContentDatabaseCollection dbs = wa.ContentDatabases;
// Get a collection of change tokens
SPChangeTokenCollection tokens = GetTokens();
// Process the changes for each database
foreach (SPContentDatabase db in dbs)
{
// Get an Id for the current database
SPPersistedObject o = db as SPPersistedObject;
Guid id = o.Id;
Console.WriteLine("\nContent database ID = {0}", id.ToString());
// Create a query.
SPChangeQuery query = new SPChangeQuery(true, true);
/* Get the starting token.
* Note that if the token is not
* found, the indexer returns null.
* Passing a null token fetches changes
* from the beginning of the log.
*/
query.ChangeTokenStart = tokens[id];
while (true)
{
// Get a batch of changes
SPChangeCollection changes = db.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);
}
// If this is the last batch, exit
if (changes.Count < query.FetchLimit)
{
// Save the last token as a starting point for the next run
tokens.Add(changes.LastChangeToken, true);
break;
}
else
{
// Starting point for next batch
query.ChangeTokenStart = changes.LastChangeToken;
}
}
}
// Persist the token collection
SaveTokens(tokens);
Console.Write("\nPress ENTER to continue...");
Console.ReadLine();
}
static SPChangeTokenCollection GetTokens()
{
SPChangeTokenCollection tokens = new SPChangeTokenCollection();
// If we have tokens from the last run, use them
if (File.Exists(DATA_FILE_PATH))
{
using (FileStream fs = File.OpenRead(DATA_FILE_PATH))
{
BinaryReader br = new BinaryReader(fs);
try
{
string s = br.ReadString();
// Construct a change token from string
tokens = new SPChangeTokenCollection(s);
}
catch (EndOfStreamException e)
{
// No serialized string, so do nothing
}
finally
{
br.Close();
}
}
}
return tokens;
}
static void SaveTokens(SPChangeTokenCollection tokens)
{
using (FileStream fs = File.Create(DATA_FILE_PATH))
{
// Serialize the tokens
BinaryWriter bw = new BinaryWriter(fs);
string s = tokens.ToString();
bw.Write(s);
// flush and close
bw.Flush();
bw.Close();
}
}
}
}
Imports System
Imports System.IO
Imports Microsoft.SharePoint
Imports Microsoft.SharePoint.Administration
Module ConsoleApp
Private Const DATA_FILE_PATH As String = "ChangeTokens.dat"
Sub Main()
' Get a collection of content databases
Dim wa As SPWebApplication = SPWebApplication.Lookup(New Uri("https://localhost"))
Dim dbs As SPContentDatabaseCollection = wa.ContentDatabases
' Get a collection of change tokens
Dim tokens As SPChangeTokenCollection = GetTokens()
' Process the changes for each database
Dim db As SPContentDatabase
For Each db In dbs
' Get an Id for the current database
Dim o As SPPersistedObject = CType(db, SPPersistedObject)
Dim id As Guid = o.Id
Console.WriteLine(vbCrLf + "Content database ID = {0}", id.ToString())
' Create a query
Dim query As New SPChangeQuery(True, True)
' Get the starting token.
' Note that if the token is not
' found, the indexer returns a null value.
' Passing a null token fetches changes
' from the beginning of the log.
query.ChangeTokenStart = tokens(id)
While (True)
' Get a batch of changes
Dim changes As SPChangeCollection = db.GetChanges(query)
' Process them
Dim change As SPChange
For Each change In changes
Console.WriteLine("Date: {0} Type of object: {1} Type of change: {2}", _
change.Time.ToShortDateString(), change.GetType().ToString(), change.ChangeType)
Next change
' If this is the last batch, exit
If changes.Count < query.FetchLimit Then
' Save the last token as a starting point for the next run
tokens.Add(changes.LastChangeToken, True)
Exit While
Else
' Starting point for next batch
query.ChangeTokenStart = changes.LastChangeToken
End If
End While
Next db
'Persist the token collection
SaveTokens(tokens)
Console.Write(vbCrLf + "Press ENTER to continue...")
Console.ReadLine()
End Sub
Function GetTokens() As SPChangeTokenCollection
Dim tokens As SPChangeTokenCollection = New SPChangeTokenCollection()
' If we have tokens from the last run, use them
If File.Exists(DATA_FILE_PATH) Then
Using fs As FileStream = File.OpenRead(DATA_FILE_PATH)
Dim br As BinaryReader = New BinaryReader(fs)
Try
Dim s As String = br.ReadString()
' Construct a change token from string
tokens = New SPChangeTokenCollection(s)
Catch e As EndOfStreamException
' No serialized string, so do nothing
Finally
br.Close()
End Try
End Using
End If
Return tokens
End Function
Sub SaveTokens(ByRef tokens As SPChangeTokenCollection)
Using fs As FileStream = File.Create(DATA_FILE_PATH)
' Serialize the tokens
Dim bw As BinaryWriter = New BinaryWriter(fs)
Dim s As String = tokens.ToString()
bw.Write(s)
' flush and close
bw.Flush()
bw.Close()
End Using
End Sub
End Module
Thread Safety
Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.
See Also
Reference
SPChangeTokenCollection Members