Sync101 with Custom Filtering

Shows how to track custom filters and how to use a standard custom provider to send changes from a filter-tracking replica to two different filtered replicas.

C# (58.2 KB)
 
 
 
 
 
(0)
1,322 times
Add to favorites
5/13/2011
E-mail Twitter del.icio.us Digg Facebook
using System;
using System.Collections.Generic;
using Microsoft.Synchronization;
using System.Text;

namespace CustomFilterSyncSample
{
    public class MyTestProgram
    {
        /// <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, with custom filter
        /// 
        /// 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)
        {           
            List<string> arguments = new List<string>(args);
            CustomerType customerType = new CustomerType();

            //Filter to get all customers in WA state
            string state = "WA";
            CustomersInstate customersInWAFilter = new CustomersInstate(state);

            FilterTrackingFullReplicaProvider<Customer> srcProvider = new FilterTrackingFullReplicaProvider<Customer>(System.Guid.NewGuid(), customerType);
            
            //Destination filtered replica with customerInWAFilter
            FilteredReplicaProvider<Customer> destProvider1 = new FilteredReplicaProvider<Customer>(System.Guid.NewGuid(), customerType, customersInWAFilter);
       
            #region Sync Source -> Destination 1 with CustomerInWAFilter           
            InitializeStoreWithItems(srcProvider);               
            srcProvider.StartTrackingFilter(customersInWAFilter);

            //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("Source Provider Contents:");
            Console.WriteLine(srcProvider.ItemsDataToString());
            Console.WriteLine("Destination Provider Contents:");
            Console.WriteLine(destProvider1.ItemsDataToString());

            SyncOrchestrator syncOrchestrator = new SyncOrchestrator();
            syncOrchestrator.Direction = SyncDirectionOrder.Upload;
            syncOrchestrator.LocalProvider = srcProvider;
            syncOrchestrator.RemoteProvider = destProvider1;

            Console.WriteLine("First sync with CustomInWAFilter ...");
            syncOrchestrator.Synchronize();

            Console.WriteLine("Show the contents of destination stores, after synchronization...");
            Console.WriteLine("Destination Provider Contents:");
            Console.WriteLine(destProvider1.ItemsDataToString());

            Console.WriteLine("Update source store...");
            UpdateStore(srcProvider);            

            Console.WriteLine("Source Provider Contents:");
            Console.WriteLine(srcProvider.ItemsDataToString());

            Console.WriteLine("Second sync with CustomInWAFilter...");
            syncOrchestrator.Synchronize();
           
            
            Console.WriteLine("Destination Provider Contents after synchronization...");
            Console.WriteLine(destProvider1.ItemsDataToString());
            #endregion

            #region Sync Source -> Destination 1 with CustomerWithRatingFilter
            
            //Filter to get all customers with rating equals to 3
            ushort rating = 3;
            CustomersWithRating customerWithRatingFilter = new CustomersWithRating(rating);

            srcProvider.StartTrackingFilter(customerWithRatingFilter);
            //Destination filtered replica with customerWithRatingFilter
            FilteredReplicaProvider<Customer> destProvider2 = new FilteredReplicaProvider<Customer>(System.Guid.NewGuid(), customerType, customerWithRatingFilter);

            //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("Source Provider Contents:");
            Console.WriteLine(srcProvider.ItemsDataToString());
            Console.WriteLine("Destination Provider Contents:");
            Console.WriteLine(destProvider2.ItemsDataToString());

            syncOrchestrator.Direction = SyncDirectionOrder.Upload;
            syncOrchestrator.LocalProvider = srcProvider;
            syncOrchestrator.RemoteProvider = destProvider2;

            Console.WriteLine("Sync with CustomWithRatingFilter... items with ratings {0}", rating);
            syncOrchestrator.Synchronize();

            Console.WriteLine("Show the contents of destination stores, after synchronization...");
            Console.WriteLine("Destination Provider Contents:");
            Console.WriteLine(destProvider2.ItemsDataToString());
            #endregion

            if (arguments.Contains("-q") != true)
            {
                Console.WriteLine("Sync has finished...");
                Console.ReadLine();
            }
        }

        static void RegisterCallbacks(BaseProvider<Customer> provider)
        {
            provider.DestinationCallbacks.FullEnumerationNeeded += new EventHandler<FullEnumerationNeededEventArgs>(DestinationCallbacks_FullEnumerationNeeded);
            provider.DestinationCallbacks.ItemChangeSkipped += new EventHandler<ItemChangeSkippedEventArgs>(DestinationCallbacks_ItemChangeSkipped);
            provider.DestinationCallbacks.ItemChanging += new EventHandler<ItemChangingEventArgs>(DestinationCallbacks_ItemChanging);
            provider.DestinationCallbacks.ItemConflicting += new EventHandler<ItemConflictingEventArgs>(DestinationCallbacks_ItemConflicting);
            provider.DestinationCallbacks.ProgressChanged += new EventHandler<SyncStagedProgressEventArgs>(DestinationCallbacks_ProgressChanged);           
        }

        #region Provider Callbacks       
        static void DestinationCallbacks_ProgressChanged(object sender, SyncStagedProgressEventArgs e)
        {
            Console.Write("Event Progress Changed: provider - {0}, ", e.ReportingProvider.ToString());
            Console.Write("stage - {0}, ", e.Stage.ToString());
            Console.WriteLine("work - {0} of {1}", e.CompletedWork, e.TotalWork);
        }

        static void DestinationCallbacks_ItemConflicting(object sender, ItemConflictingEventArgs e)
        {
            Console.Write("Event Item conflicting: source data - {0}, ", e.SourceChangeData != null ? e.SourceChangeData.ToString() : null);
            Console.WriteLine("destination data - {0}", e.DestinationChangeData != null ? e.DestinationChangeData.ToString() : null);
            e.SetResolutionAction(ConflictResolutionAction.Merge);
        }

        static void DestinationCallbacks_ItemChanging(object sender, ItemChangingEventArgs e)
        {
            Console.Write("Event Item changing: item - {0}, ", e.Item.ItemId.ToString());
            Console.WriteLine("change kind - {0}", e.Item.ChangeKind.ToString());
        }

        static void DestinationCallbacks_ItemChangeSkipped(object sender, ItemChangeSkippedEventArgs e)
        {
            Console.Write("Event Item Change Skipped: provider {0}, ", e.ReportingProvider.ToString());
            Console.Write("stage - {0}, ", e.Stage.ToString());
            Console.WriteLine("item  - {0} ", e.ItemChange.ItemId.ToString());
        }

        static void DestinationCallbacks_FullEnumerationNeeded(object sender, FullEnumerationNeededEventArgs e)
        {
            FullEnumerationAction action = FullEnumerationAction.Full;  // This can be changed by the application to control if full enumeration is FZull, Partial, or Aborted.
            Console.Write("Event Full Enumeration Needed: old action {0}, ", e.Action.ToString());
            Console.WriteLine("new action - {0} ", action.ToString());
            e.Action = action;
        }
        #endregion

        #region Private Methods
        static SyncableItem<Customer>[] InitializeStoreWithItems(BaseProvider<Customer> provider)
        {
            SyncableItem<Customer>[] items = new SyncableItem<Customer>[itemCount];
            

            for (uint index = 0; index < itemCount; index++)
            {
                SyncableItem<Customer> item = provider.CreateItem(itemGuids[index]);
                items[index] = item;
                item.Item.Rating = (ushort)(index + 1);
                item.Item.PhoneNumber = samplePhoneNumber;               
                item.Item.State = states[index];                                
            }

            return items;
        }

        static void UpdateStore(BaseProvider<Customer> provider)
        {            
            ulong providerTickCount = provider.GetNextTickCount();
            SortedDictionary<SyncId,SyncableItem<Customer>>.Enumerator enumerator =  provider.GetEnumerator();
            SyncVersion updateVersion = new SyncVersion(0, providerTickCount);
            string lastUpdateValue = "";
            int updateCount=0;
            
            //Make only 2 updates. One for Move in and Move out.
            while (updateCount < 2 && enumerator.MoveNext())
            {
                SyncableItem<Customer> item = enumerator.Current.Value;

                if (lastUpdateValue != "CA" && item.Item.State == "WA")
                {
                    //Move out...that is, moving out of the filter criterea                    
                    item.Item.State = "CA";
                    item.CurrentVersion = updateVersion;
                    lastUpdateValue = "CA";
                    updateCount++;
                }
                else if(lastUpdateValue != "WA")
                {
                    //Item moving in to the filter criterea
                    item.Item.State = "WA";
                    item.CurrentVersion = updateVersion;
                    lastUpdateValue = "WA";
                    updateCount++;
                }
            }  
            
           
            provider.PrepareForSync();
        }        
        #endregion

        #region Private Fields
        const uint itemCount = 4;
        const uint itemsInStoreFrequency = 4;
        static string[] states = { "WA", "OR", "CA", "FL" };
        static Guid[] itemGuids = { new Guid("3E11A080-7A01-423c-BDCC-5F85D9366AE0"),
                                    new Guid("6DBB4851-9152-4979-8E9C-C38B93EE2B37"),
                                    new Guid("5C55D622-A9E7-47f0-8FDD-437BB4549BA7"),
                                    new Guid("FC8D01C1-921C-4023-9ECC-B008956DA1E9")};
        const string samplePhoneNumber = "11111111";
        #endregion Private Fields
    }
}