static MyProviderFactory() { Guid[] itemIds = new Guid[9]; itemIds[1] = new Guid("11111111-1111-1111-1111-111111111111"); itemIds[2] = new Guid("22222222-2222-2222-2222-222222222222"); itemIds[3] = new Guid("33333333-3333-3333-3333-333333333333"); itemIds[4] = new Guid("44444444-4444-4444-4444-444444444444"); itemIds[5] = new Guid("55555555-5555-5555-5555-555555555555"); itemIds[6] = new Guid("66666666-6666-6666-6666-666666666666"); itemIds[7] = new Guid("77777777-7777-7777-7777-777777777777"); itemIds[8] = new Guid("88888888-8888-8888-8888-888888888888"); storeA.CreateItem(new ItemData(DATA, "1"), itemIds[1]); storeA.CreateItem(new ItemData(DATA, "2"), itemIds[2]); storeA.CreateItem(new ItemData(DATA, "7"), itemIds[7]); storeA.CreateItem(new ItemData(DATA, "8"), itemIds[8]); storeA.CreateItem(new ItemData(DATA, "3"), itemIds[3]); storeA.CreateItem(new ItemData(DATA, "4"), itemIds[4]); storeB.CreateItem(new ItemData(DATA, "5"), itemIds[5]); storeB.CreateItem(new ItemData(DATA, "6"), itemIds[6]); }
//Save the item, taking the appropriate action for the 'change' and the data from the item (in 'context') public void SaveItemChange(SaveChangeAction saveChangeAction, ItemChange change, SaveChangeContext context) { Thread.Sleep(1000); ulong timeStamp = 0; ItemMetadata item = null; ItemData data = null; change.WorkEstimate = 1; switch (saveChangeAction) { case SaveChangeAction.Create: //Do duplicate detection here item = _metadata.FindItemMetadataById(change.ItemId); if (null != item) { throw new Exception("SaveItemChange must not have Create action for existing items."); } item = _metadata.CreateItemMetadata(change.ItemId, change.CreationVersion); item.ChangeVersion = change.ChangeVersion; data = new ItemData((ItemData)context.ChangeData); //We are using the same id for both the local and global item id. _store.CreateItem(data, change.ItemId.GetGuidId()); SaveItemMetadata(item, _store.Get(change.ItemId.GetGuidId()).TimeStamp); break; case SaveChangeAction.UpdateVersionAndData: case SaveChangeAction.UpdateVersionOnly: item = _metadata.FindItemMetadataById(change.ItemId); if (null == item) { throw new Exception("Item Not Found in Store!?"); } item.ChangeVersion = change.ChangeVersion; if (saveChangeAction == SaveChangeAction.UpdateVersionOnly) { SaveItemMetadata(item); } else //Also update the data and the timestamp. { data = new ItemData((ItemData)context.ChangeData); timeStamp = _store.UpdateItem(item.GlobalId.GetGuidId(), data); SaveItemMetadata(item, timeStamp); } break; case SaveChangeAction.DeleteAndStoreTombstone: item = _metadata.FindItemMetadataById(change.ItemId); if (null == item) { item = _metadata.CreateItemMetadata(change.ItemId, change.CreationVersion); } if (change.ChangeKind == ChangeKind.Deleted) { item.MarkAsDeleted(change.ChangeVersion); } else { // This should never happen in Sync Framework V1.0 throw new Exception("Invalid ChangeType"); } item.ChangeVersion = change.ChangeVersion; SaveItemMetadata(item, 0); // set timestamp to 0 for tombstones _store.DeleteItem(item.GlobalId.GetGuidId()); break; //Merge the changes! (Take the data from the local item + the remote item),noting to update the tick count to propagate the resolution! case SaveChangeAction.UpdateVersionAndMergeData: item = _metadata.FindItemMetadataById(change.ItemId); if (null == item) { throw new Exception("Item Not Found in Store!?"); } if (item.IsDeleted != true) { //Note - you must update the change version to propagate the resolution! item.ChangeVersion = new SyncVersion(0, _metadata.GetNextTickCount()); //Combine the conflicting data... ItemData mergedData = (_store.Get(item.GlobalId.GetGuidId())).Merge((ItemData)context.ChangeData); timeStamp = _store.UpdateItem(item.GlobalId.GetGuidId(), mergedData); SaveItemMetadata(item, timeStamp); } break; case SaveChangeAction.DeleteAndRemoveTombstone: item = _metadata.FindItemMetadataById(change.ItemId); if (item != null) { List <SyncId> ids = new List <SyncId>(); ids.Add(item.GlobalId); _metadata.RemoveItemMetadata(ids); } _store.DeleteItem(change.ItemId.GetGuidId()); break; } }
/// <summary> /// This is an extension of an in-memory provider sample that is used to illustrate the responsibilites of a provider working on behalf /// of a store. For instance, what do do with an item create/update/delete, how to get changes, how to apply changes, how to detect conflicts, /// and how to resolve them using a custom action such as merge... /// /// Please note that this sample is most useful with breakpoints in MyTestProgram.cs to find out HOW synchronization using the /// Microsoft Sync Framework works. This sample is not designed to be a boot-strapper like the NTFS providers for native and managed... /// </summary> /// <param name="args"></param> public static void Main(string[] args) { const string DATA = "data"; string providerA = "A"; string providerB = "B"; string providerC = "C"; List<string> arguments = new List<string>(args); //start clean CleanUpProvider(providerA); CleanUpProvider(providerB); CleanUpProvider(providerC); //Initialize the stores storeA = new MySimpleDataStore(); storeB = new MySimpleDataStore(); storeC = new MySimpleDataStore(); //Create items on each store using a global ID and the data of the item (Note, in order to verify results against //a baseline we are using hardcoded global ids for the items. In a real application CreateItem should be called without //the Guid parameter, which would generate a new Guid id and return it. Guid[] itemIds = new Guid[9]; itemIds[1] = new Guid("11111111-1111-1111-1111-111111111111"); itemIds[2] = new Guid("22222222-2222-2222-2222-222222222222"); itemIds[3] = new Guid("33333333-3333-3333-3333-333333333333"); itemIds[4] = new Guid("44444444-4444-4444-4444-444444444444"); itemIds[5] = new Guid("55555555-5555-5555-5555-555555555555"); itemIds[6] = new Guid("66666666-6666-6666-6666-666666666666"); itemIds[7] = new Guid("77777777-7777-7777-7777-777777777777"); itemIds[8] = new Guid("88888888-8888-8888-8888-888888888888"); storeA.CreateItem(new ItemData(DATA, "1"), itemIds[1]); storeA.CreateItem(new ItemData(DATA, "2"), itemIds[2]); storeA.CreateItem(new ItemData(DATA, "7"), itemIds[7]); storeA.CreateItem(new ItemData(DATA, "8"), itemIds[8]); storeB.CreateItem(new ItemData(DATA, "3"), itemIds[3]); storeB.CreateItem(new ItemData(DATA, "4"), itemIds[4]); storeC.CreateItem(new ItemData(DATA, "5"), itemIds[5]); storeC.CreateItem(new ItemData(DATA, "6"), itemIds[6]); //Show the contents of the stores, prior to ANY any synchronization... Console.WriteLine("Show the contents of the stores, prior to any synchronization..."); Console.WriteLine(new MySyncProvider(providerA, storeA).ToString()); Console.WriteLine(storeA.ToString()); Console.WriteLine(new MySyncProvider(providerB, storeB).ToString()); Console.WriteLine(storeB.ToString()); Console.WriteLine(new MySyncProvider(providerC, storeC).ToString()); Console.WriteLine(storeC.ToString()); //Sync providers A and provider B DoBidirectionalSync(providerA, storeA, providerB, storeB); if (arguments.Contains("-q") != true) { Console.WriteLine("Sync has finished..."); Console.ReadLine(); } //Create an update-update conflict on item 1 and show merge... (Note - this sample handles update-update conflicts and simply merges the data) Console.WriteLine("A and B are going to create a conflict on item 1. A writes 'Did Merging' and B writes 'Work?'"); //Create an update-update conflict to merge... storeA.UpdateItem(itemIds[1], new ItemData(DATA, "Did Merging")); storeB.UpdateItem(itemIds[1], new ItemData(DATA, " Work?")); //Sync providers A and provider B DoBidirectionalSync(providerA, storeA, providerB, storeB); //Delete an item on B and show that the delete propagates Console.WriteLine("Deleting item '4' on B"); storeB.DeleteItem(itemIds[4]); //Sync B and C DoBidirectionalSync(providerB, storeB, providerC, storeC); //Close the sync loop by syncing A and C Console.WriteLine("Closing the \"sync loop\" by syncing A and C..."); DoBidirectionalSync(providerA, storeA, providerC, storeC); //Delete item 2 on B Console.WriteLine("{0}Deleting item '2' on B.", Environment.NewLine); storeB.DeleteItem(itemIds[2]); // Sync B and C DoBidirectionalSync(providerB, storeB, providerC, storeC); //Cleanup Tombstones on B Console.WriteLine("{0}Clean up Tombstones on B.", Environment.NewLine); new MySyncProvider(providerB, storeB).CleanupTombstones(TimeSpan.Zero); // Sync B and C DoBidirectionalSync(providerB, storeB, providerC, storeC); //Close the sync loop by syncing A and C DoBidirectionalSync(providerA, storeA, providerC, storeC); if (arguments.Contains("-q") != true) { Console.WriteLine("Sync has finished..."); Console.ReadLine(); } }
/// <summary> /// This is an extension of an in-memory provider sample that is used to illustrate the responsibilites of a provider working on behalf /// of a store. For instance, what do do with an item create/update/delete, how to get changes, how to apply changes, how to detect conflicts, /// and how to resolve them using a custom action such as merge... /// /// Please note that this sample is most useful with breakpoints in MyTestProgram.cs to find out HOW synchronization using the /// Microsoft Sync Framework works. This sample is not designed to be a boot-strapper like the NTFS providers for native and managed... /// </summary> /// <param name="args"></param> public static void Main(string[] args) { const string DATA = "data"; string providerA = "A"; string providerB = "B"; string providerC = "C"; List <string> arguments = new List <string>(args); //start clean CleanUpProvider(providerA); CleanUpProvider(providerB); CleanUpProvider(providerC); //Initialize the stores storeA = new MySimpleDataStore(); storeB = new MySimpleDataStore(); storeC = new MySimpleDataStore(); //Create items on each store using a global ID and the data of the item (Note, in order to verify results against //a baseline we are using hardcoded global ids for the items. In a real application CreateItem should be called without //the Guid parameter, which would generate a new Guid id and return it. Guid[] itemIds = new Guid[9]; itemIds[1] = new Guid("11111111-1111-1111-1111-111111111111"); itemIds[2] = new Guid("22222222-2222-2222-2222-222222222222"); itemIds[3] = new Guid("33333333-3333-3333-3333-333333333333"); itemIds[4] = new Guid("44444444-4444-4444-4444-444444444444"); itemIds[5] = new Guid("55555555-5555-5555-5555-555555555555"); itemIds[6] = new Guid("66666666-6666-6666-6666-666666666666"); itemIds[7] = new Guid("77777777-7777-7777-7777-777777777777"); itemIds[8] = new Guid("88888888-8888-8888-8888-888888888888"); storeA.CreateItem(new ItemData(DATA, "1"), itemIds[1]); storeA.CreateItem(new ItemData(DATA, "2"), itemIds[2]); storeA.CreateItem(new ItemData(DATA, "7"), itemIds[7]); storeA.CreateItem(new ItemData(DATA, "8"), itemIds[8]); storeB.CreateItem(new ItemData(DATA, "3"), itemIds[3]); storeB.CreateItem(new ItemData(DATA, "4"), itemIds[4]); storeC.CreateItem(new ItemData(DATA, "5"), itemIds[5]); storeC.CreateItem(new ItemData(DATA, "6"), itemIds[6]); //Show the contents of the stores, prior to ANY any synchronization... Console.WriteLine("Show the contents of the stores, prior to any synchronization..."); Console.WriteLine(new MySyncProvider(providerA, storeA).ToString()); Console.WriteLine(storeA.ToString()); Console.WriteLine(new MySyncProvider(providerB, storeB).ToString()); Console.WriteLine(storeB.ToString()); Console.WriteLine(new MySyncProvider(providerC, storeC).ToString()); Console.WriteLine(storeC.ToString()); //Sync providers A and provider B DoBidirectionalSync(providerA, storeA, providerB, storeB); if (arguments.Contains("-q") != true) { Console.WriteLine("Sync has finished..."); Console.ReadLine(); } //Create an update-update conflict on item 1 and show merge... (Note - this sample handles update-update conflicts and simply merges the data) Console.WriteLine("A and B are going to create a conflict on item 1. A writes 'Did Merging' and B writes 'Work?'"); //Create an update-update conflict to merge... storeA.UpdateItem(itemIds[1], new ItemData(DATA, "Did Merging")); storeB.UpdateItem(itemIds[1], new ItemData(DATA, " Work?")); //Sync providers A and provider B DoBidirectionalSync(providerA, storeA, providerB, storeB); //Delete an item on B and show that the delete propagates Console.WriteLine("Deleting item '4' on B"); storeB.DeleteItem(itemIds[4]); //Sync B and C DoBidirectionalSync(providerB, storeB, providerC, storeC); //Close the sync loop by syncing A and C Console.WriteLine("Closing the \"sync loop\" by syncing A and C..."); DoBidirectionalSync(providerA, storeA, providerC, storeC); //Delete item 2 on B Console.WriteLine("{0}Deleting item '2' on B.", Environment.NewLine); storeB.DeleteItem(itemIds[2]); // Sync B and C DoBidirectionalSync(providerB, storeB, providerC, storeC); //Cleanup Tombstones on B Console.WriteLine("{0}Clean up Tombstones on B.", Environment.NewLine); new MySyncProvider(providerB, storeB).CleanupTombstones(TimeSpan.Zero); // Sync B and C DoBidirectionalSync(providerB, storeB, providerC, storeC); //Close the sync loop by syncing A and C DoBidirectionalSync(providerA, storeA, providerC, storeC); if (arguments.Contains("-q") != true) { Console.WriteLine("Sync has finished..."); Console.ReadLine(); } }