How to: Create a Managed Synchronization Provider
This topic describes how to use a managed language to create a Sync Framework synchronization provider that synchronizes data from a custom data store.
This topic assumes a basic familiarity with C# and Microsoft .NET Framework concepts.
The examples in this topic focus on the following Sync Framework classes and interfaces:
Understanding Synchronization Providers
A synchronization provider is a software component that represents a replica during synchronization. This enables the replica to synchronize its data with other replicas. For synchronization to occur, an application first creates a SyncOrchestrator object, connects it to two SyncProvider objects, and then starts synchronization. One of the providers represents the source replica. The source replica supplies metadata for changed items through its GetChangeBatch(UInt32, SyncKnowledge, Object) method and item data through an IChangeDataRetriever object. The other provider represents the destination replica. The destination replica receives metadata for changed items through its ProcessChangeBatch(ConflictResolutionPolicy, ChangeBatch, Object, SyncCallbacks, SyncSessionStatistics) method and applies the changes to its item store by using a Sync Framework-supplied NotifyingChangeApplier object together with its own INotifyingChangeApplierTarget object.
For more information about the role of the synchronization provider, see Implementing a Standard Custom Provider.
Build Requirements
.NET Framework 2.0 or later.
Reference to Microsoft.Synchronization.
Reference to Microsoft.Synchronization.MetadataStorage.
Example
The example code in this topic shows how to implement the basic class and interface methods that are required for a replica to participate in a Sync Framework synchronization community, both as a source and as a destination. The replica in this example is a text file that stores contact information as a list of comma-separated values. The items to synchronize are the contacts that are contained in this file. This example also uses a custom metadata store that is implemented by using the metadata storage service API. For information about the metadata storage service, see Sync Framework Metadata Storage Service.
In the following examples, _itemStore represents an object that contains both the item store and the metadata store.
Implementing SyncProvider and KnowledgeSyncProvider
The entry point into the provider is the SyncProvider class. This class is intended to function as a base class for other, more powerful provider classes. This example uses the KnowledgeSyncProvider class.
Declaring KnowledgeSyncProvider
Add KnowledgeSyncProvider to the class inheritance list.
Add the SyncProvider and KnowledgeSyncProvider methods to the class.
IdFormats Property
Sync Framework calls IdFormats on both the source and destination providers when Synchronize is called on the SyncOrchestrator object. The IdFormats property returns the ID format schema that is used by the provider. This schema must be the same for both providers. This example defines sizes for item IDs that contain a SyncGlobalId, replica IDs that contain the absolute path of the replica, and change unit IDs that are members of an enumeration.
BeginSession Method
Sync Framework calls BeginSession(SyncProviderPosition, SyncSessionContext) on both the source and destination providers before it calls any other methods. This method informs a provider that it is joining a synchronization session and passes the provider an object that contains session state information. This implementation stores the session state object or throws SyncInvalidOperationException if the provider has already joined a synchronization session.
GetSyncBatchParameters Method
Sync Framework calls GetSyncBatchParameters(UInt32, SyncKnowledge) on the destination provider. This method retrieves the number of changes the source provider should include in a change batch, and obtains the destination provider's current knowledge. This implementation extracts the knowledge from the metadata store, and sets the batch size to 10.
The metadata store object returns the current knowledge of the replica by using GetKnowledge. This implementation creates a new SyncKnowledge object if the replica does not yet contain any knowledge, and sets the tick count of the knowledge to the current tick count of the replica.
GetChangeBatch Method
The synchronization session starts in earnest when Sync Framework calls GetChangeBatch(UInt32, SyncKnowledge, Object) on the source provider. This method retrieves a batch of changes to send to the destination provider and also returns the data retriever interface. Sync Framework uses the data retriever interface to obtain an object that the destination provider uses to retrieve item data for changes that are applied to the destination replica. Sync Framework calls GetChangeBatch(UInt32, SyncKnowledge, Object) repeatedly until the last batch is sent. The source provider indicates that a batch is the last batch by calling the SetLastBatch method on the change batch object. This implementation delegates the change enumeration task to the metadata store object. The provider object implements IChangeDataRetriever; therefore, it is returned in the changeDataRetriever parameter.
The metadata store object returns a batch of changes by using GetChangeBatch(UInt32, SyncKnowledge). This implementation stores items in the metadata store as a list of ItemMetadata objects that are ordered by item ID. The items are enumerated and a change is added to an ordered group in the change batch object if the change is not contained in the destination knowledge. When all items in the metadata store have been enumerated, SetLastBatch is called on the change batch.
ProcessChangeBatch Method
After Sync Framework has obtained a batch of changes from the source provider by calling its GetChangeBatch(UInt32, SyncKnowledge, Object) method, Sync Framework calls ProcessChangeBatch(ConflictResolutionPolicy, ChangeBatch, Object, SyncCallbacks, SyncSessionStatistics) on the destination provider. This method applies the changes to the destination replica. This method is called one time for each change batch that is retrieved from GetChangeBatch(UInt32, SyncKnowledge, Object) on the source provider. This implementation uses the metadata store object to obtain local version information for items from the source provider. It then creates a NotifyingChangeApplier object implemented by Sync Framework and calls its ApplyChanges(ConflictResolutionPolicy, ChangeBatch, IChangeDataRetriever, IEnumerableItemChange, SyncKnowledge, ForgottenKnowledge, INotifyingChangeApplierTarget, SyncSessionContext, SyncCallbacks) method.
The metadata store object returns local version information for items from the source provider by using GetLocalVersions(ChangeBatch). This implementation enumerates the changes sent in the change batch from the source provider. If an item is in the destination metadata, its version information is added to a list of changes that contain the version information. If an item does not exist in the destination metadata, it is flagged as an unknown item in the local version list.
EndSession Method
After the source provider sends its last batch and the destination provider has applied the changes to its data store, Sync Framework calls EndSession(SyncSessionContext) on both the source and destination providers. This method informs a provider that it is leaving a synchronization session and should free any resources that are associated with the session. This implementation frees the session state object that it stored in the BeginSession(SyncProviderPosition, SyncSessionContext) call or throws SyncInvalidOperationException if the provider did not previously join a synchronization session.
Methods That Are Not Implemented
The following methods are not required because this sample never removes items marked as deleted in the metadata store. These methods can throw NotImplementedException:
Implementing INotifyingChangeApplierTarget
This interface is provided to Sync Framework when the destination provider calls the ApplyChanges(ConflictResolutionPolicy, ChangeBatch, IChangeDataRetriever, IEnumerableItemChange, SyncKnowledge, ForgottenKnowledge, INotifyingChangeApplierTarget, SyncSessionContext, SyncCallbacks) method, typically in the ProcessChangeBatch(ConflictResolutionPolicy, ChangeBatch, Object, SyncCallbacks, SyncSessionStatistics) method. INotifyingChangeApplierTarget contains methods that are called during change application. These methods are only called on the destination provider.
Declaring INotifyingChangeApplierTarget
Add INotifyingChangeApplierTarget to your class inheritance list.
Add the INotifyingChangeApplierTarget methods to your class.
IdFormats Property
Sync Framework calls IdFormats to retrieve the ID format schema of the provider. This example uses the same class to implement both KnowledgeSyncProvider and INotifyingChangeApplierTarget. Therefore, this implementation is the same as that for the IdFormats property of KnowledgeSyncProvider, above.
GetNextTickCount
Sync Framework calls GetNextTickCount to increment and retrieve the tick count for the replica. This implementation calls the GetNextTickCount method of the metadata store object.
The metadata store implementation of GetNextTickCount increments the tick count of the replica and returns it.
SaveItemChange
During change application, Sync Framework calls SaveItemChange(SaveChangeAction, ItemChange, SaveChangeContext) for each change that is to be applied to the destination replica. This implementation updates the item store and metadata store for each type of change received. When an item is created or updated, the item data is received in the ChangeData property of the context parameter. The ChangeData property contains the object returned from the LoadChangeData(LoadChangeContext) method of the source provider. After the change is applied, the updated destination knowledge is stored.
In the following examples, _ContactItemMetaList contains ItemMetadata objects.
The UpdateContactFromSync method of the contact store updates the specified contact. If the contact does not exist, a new contact is created and added to the contact store. The metadata store is also updated to reflect changes to the contact store.
The UpdateContactVersion method of the contact store updates the version metadata for the specified item.
The DeleteContactFromSync method of the contact store removes the item from the contact store and marks the item as deleted in the metadata store.
StoreKnowledgeForScope
After processing each change batch, Sync Framework calls StoreKnowledgeForScope(SyncKnowledge, ForgottenKnowledge) so that the destination provider can save the knowledge that contains the new changes. This implementation saves the knowledge objects to the metadata store and overwrites previously existing knowledge. Changes made to the contact store and to the metadata store during processing of the change batch are committed to the files on the disk.
The SaveMetadataChanges method of the contact store commits changes made to the metadata store to the file on disk.
Methods That Are Not Implemented
The following methods are not required for basic synchronization scenarios and can throw NotImplementedException:
Implementing IChangeDataRetriever
IChangeDataRetriever is returned to Sync Framework by the source provider in response to the GetChangeBatch(UInt32, SyncKnowledge, Object) call. IChangeDataRetriever is sent to the destination provider in the ProcessChangeBatch(ConflictResolutionPolicy, ChangeBatch, Object, SyncCallbacks, SyncSessionStatistics) call, where it is typically passed on to the ApplyChanges(ConflictResolutionPolicy, ChangeBatch, IChangeDataRetriever, IEnumerableItemChange, SyncKnowledge, ForgottenKnowledge, INotifyingChangeApplierTarget, SyncSessionContext, SyncCallbacks) method of a change applier. The change applier then calls LoadChangeData(LoadChangeContext) to obtain an object that represents the item data. The change applier passes this interface to the SaveItemChange(SaveChangeAction, ItemChange, SaveChangeContext) or SaveChangeWithChangeUnits(ItemChange, SaveChangeWithChangeUnitsContext) method of the destination provider. The destination provider uses this object to retrieve item data for new or changed items and applies the item data to the destination replica.
Declaring IChangeDataRetriever
Add IChangeDataRetriever to the class inheritance list.
Add the IChangeDataRetriever methods to the class.
IdFormats Property
Sync Framework calls IdFormats to retrieve the ID format schema of the provider. This example uses the same class to implement both KnowledgeSyncProvider and IChangeDataRetriever. Therefore, this implementation is the same as that for the IdFormats property of KnowledgeSyncProvider, above.
LoadChangeData Method
During change application, Sync Framework calls LoadChangeData(LoadChangeContext) to obtain an object that the destination provider can use to retrieve item data. This implementation returns the contact data serialized as a string.
Next Steps
Next, you might want to create an application that can host the synchronization session and connect it to the provider. For information about how to do this, see How to: Create an Unmanaged Synchronization Application.
You can also enhance the provider to filter the items or change units that are synchronized. For more information about filtering, see Filtering Synchronization Data.
You can also enhance the provider to handle change units. For more information about change units, see Synchronizing Change Units.
You might also want to create a custom metadata store. For more information about how to handle synchronization metadata, see Managing Metadata for Standard Providers.