internal FileSystemUpdateFailedEventArgs(ISyncProvider fileSystem, FileSystemChange change, Exception exception) { this.FileSystem = fileSystem; this.Entry = change.Entry; this.ChangeType = change.ChangeType; this.Exception = exception; }
private IEnumerable <SyncProfileOption> GetProfileOptions(ISyncProvider provider, SyncTarget target, User user) { var hasQuality = provider as IHasSyncQuality; if (hasQuality != null) { return(hasQuality.GetProfileOptions(target)); } var list = new List <SyncProfileOption>(); list.Add(new SyncProfileOption { Name = "Original", Id = "Original", Description = "Syncs original files as-is.", EnableQualityOptions = false }); if (user == null || user.Policy.EnableSyncTranscoding) { list.Add(new SyncProfileOption { Name = "Baseline", Id = "baseline", Description = "Designed for compatibility with all devices, including web browsers. Targets H264/AAC video and MP3 audio." }); list.Add(new SyncProfileOption { Name = "General", Id = "general", Description = "Designed for compatibility with Chromecast, Roku, Smart TV's, and other similar devices. Targets H264/AAC/AC3 video and MP3 audio.", IsDefault = true }); } return(list); }
public void ApplyChangesWhile(ISyncProvider fileSystem, IEnumerable<FileSystemChange> changes, Func<bool> stopCheck) { foreach (var change in changes) { if (stopCheck() == true) break; FileSystemEntry newEntry = null; try { if (change.ChangeType == FileSystemChangeType.Create) { newEntry = fileSystem.Create(change.Entry); } else if (change.ChangeType == FileSystemChangeType.Delete) { fileSystem.Delete(change.Entry); } else if (change.ChangeType == FileSystemChangeType.Overwrite) { fileSystem.Delete(change.Entry); newEntry = fileSystem.Create(change.Entry); } if (newEntry != null && change.Entry.Created != null) newEntry.SetCreationTime(change.Entry.Created.Value); if (newEntry != null && change.Entry.Modified != null) newEntry.SetModificationTime(change.Entry.Modified.Value); NotifyFileSystemUpdated(fileSystem, change); } catch (Exception ex) { NotifyFileSystemUpdateFailed(fileSystem, change, ex); } } }
private IEnumerable<SyncTarget> GetSyncTargets(ISyncProvider provider, string userId) { return provider.GetSyncTargets(userId).Select(i => new SyncTarget { Name = i.Name, Id = GetSyncTargetId(provider, i) }); }
private IEnumerable<SyncProfileOption> GetProfileOptions(ISyncProvider provider, SyncTarget target, User user) { var hasQuality = provider as IHasSyncQuality; if (hasQuality != null) { return hasQuality.GetProfileOptions(target); } var list = new List<SyncProfileOption>(); list.Add(new SyncProfileOption { Name = "Original", Id = "Original", Description = "Syncs original files as-is.", EnableQualityOptions = false }); if (user == null || user.Policy.EnableSyncTranscoding) { list.Add(new SyncProfileOption { Name = "Baseline", Id = "baseline", Description = "Designed for compatibility with all devices, including web browsers. Targets H264/AAC video and MP3 audio." }); list.Add(new SyncProfileOption { Name = "General", Id = "general", Description = "Designed for compatibility with Chromecast, Roku, Smart TV's, and other similar devices. Targets H264/AAC/AC3 video and MP3 audio.", IsDefault = true }); } return list; }
private SyncJobOptions GetSyncJobOptions(ISyncProvider provider, SyncTarget target, string profile, string quality) { var hasProfile = provider as IHasSyncQuality; if (hasProfile != null) { return hasProfile.GetSyncJobOptions(target, profile, quality); } return GetDefaultSyncJobOptions(profile, quality); }
private async Task Test1( BlogDbContext localDb, ISyncProvider localSyncProvider, BlogDbContext remoteDb, ISyncProvider remoteSyncProvider) { var localStoreId = await localSyncProvider.GetStoreIdAsync(); var remoteStoreId = await remoteSyncProvider.GetStoreIdAsync(); var initialLocalSet = await localSyncProvider.GetChangesAsync(remoteStoreId); var initialRemoteSet = await remoteSyncProvider.GetChangesAsync(localStoreId); Assert.IsNotNull(initialRemoteSet); Assert.IsNotNull(initialRemoteSet.Items); Assert.AreEqual(0, initialRemoteSet.Items.Count); Assert.IsNotNull(initialLocalSet); Assert.IsNotNull(initialLocalSet.Items); Assert.AreEqual(0, initialLocalSet.Items.Count); var newUser = new User() { Email = "*****@*****.**", Name = "User1", Created = new DateTime(2019, 1, 1) }; remoteDb.Users.Add(newUser); await remoteDb.SaveChangesAsync(); var changeSetAfterUserAdd = await remoteSyncProvider.GetChangesAsync(localStoreId); Assert.IsNotNull(changeSetAfterUserAdd); Assert.IsNotNull(changeSetAfterUserAdd.Items); Assert.AreEqual(1, changeSetAfterUserAdd.Items.Count); Assert.AreEqual(ChangeType.Insert, changeSetAfterUserAdd.Items[0].ChangeType); Assert.AreEqual(newUser.Email, changeSetAfterUserAdd.Items[0].Values["Email"]); Assert.AreEqual(newUser.Name, changeSetAfterUserAdd.Items[0].Values["Name"]); var finalLocalAnchor = await localSyncProvider.ApplyChangesAsync(changeSetAfterUserAdd); Assert.IsNotNull(finalLocalAnchor); //try to apply same changeset result in an exception var exception = await Assert.ThrowsExceptionAsync <InvalidSyncOperationException>(() => localSyncProvider.ApplyChangesAsync(changeSetAfterUserAdd)); Assert.IsNotNull(exception); newUser.Created = new DateTime(2018, 1, 1); await remoteDb.SaveChangesAsync(); { //after saved changes version should be updated as well at 2 var changeSetAfterUserEdit = await remoteSyncProvider.GetChangesAsync(localStoreId); Assert.IsNotNull(changeSetAfterUserEdit); Assert.IsNotNull(changeSetAfterUserEdit.Items); Assert.AreEqual(1, changeSetAfterUserEdit.Items.Count); Assert.AreEqual(newUser.Email, changeSetAfterUserEdit.Items[0].Values["Email"]); Assert.AreEqual(newUser.Name, changeSetAfterUserEdit.Items[0].Values["Name"]); Assert.AreEqual(newUser.Created, changeSetAfterUserEdit.Items[0].Values["Created"]); } { //now let's change same record in local database and try to apply changes to remote db //this should result in a conflict var newUserInLocalDb = await localDb.Users.FirstAsync(_ => _.Name == newUser.Name); newUserInLocalDb.Name = "modified-name"; await localDb.SaveChangesAsync(); //get changes from local db var localChangeSet = await localSyncProvider.GetChangesAsync(remoteStoreId); Assert.IsNotNull(localChangeSet); //try to apply changes to remote provider var anchorAfterChangesAppliedFromLocalProvider = await remoteSyncProvider.ApplyChangesAsync(localChangeSet); //given we didn't provide a resolution function for the conflict provider just skip //to apply the changes from local db //so nothing should be changed in remote db Assert.IsNotNull(anchorAfterChangesAppliedFromLocalProvider); var userNotChangedInRemoteDb = await remoteDb.Users.FirstAsync(_ => _.Email == newUser.Email); Assert.IsNotNull(userNotChangedInRemoteDb); Assert.AreEqual(newUser.Name, userNotChangedInRemoteDb.Name); Assert.AreEqual(newUser.Created, userNotChangedInRemoteDb.Created); //ok now try apply changes but forcing any write on remote store on conflict anchorAfterChangesAppliedFromLocalProvider = await remoteSyncProvider.ApplyChangesAsync(localChangeSet, (item) => { //assert that conflict occurred on item we just got from local db Assert.IsNotNull(item); Assert.AreEqual(newUserInLocalDb.Email, item.Values["Email"]); Assert.AreEqual(newUserInLocalDb.Name, item.Values["Name"]); Assert.AreEqual(ChangeType.Update, item.ChangeType); //force write in remote store return(ConflictResolution.ForceWrite); }); //now we should have a new version (+1) Assert.IsNotNull(anchorAfterChangesAppliedFromLocalProvider); //and local db changes should be applied to remote db var userChangedInRemoteDb = await remoteDb.Users.AsNoTracking().FirstAsync(_ => _.Email == newUser.Email); Assert.IsNotNull(userChangedInRemoteDb); Assert.AreEqual(newUserInLocalDb.Name, userChangedInRemoteDb.Name); Assert.AreEqual(newUserInLocalDb.Created, userChangedInRemoteDb.Created); } { //now let's try to update a deleted record remoteDb.Users.Remove(newUser); await remoteDb.SaveChangesAsync(); var newUserInLocalDb = await localDb.Users.FirstAsync(_ => _.Email == newUser.Email); var localChangeSet = await localSyncProvider.GetChangesAsync(remoteStoreId); Assert.IsNotNull(localChangeSet); //try to apply changes to remote provider var anchorAfterChangesAppliedFromLocalProvider = await remoteSyncProvider.ApplyChangesAsync(localChangeSet); //given we didn't provide a resolution function for the conflict provider just skip //to apply the changes from local db //so nothing should be changed in remote db Assert.IsNotNull(anchorAfterChangesAppliedFromLocalProvider); //user should not be present var userNotChangedInRemoteDb = await remoteDb.Users.FirstOrDefaultAsync(_ => _.Email == newUser.Email); Assert.IsNull(userNotChangedInRemoteDb); //ok now try apply changes but forcing any write on remote store on conflict anchorAfterChangesAppliedFromLocalProvider = await remoteSyncProvider.ApplyChangesAsync(localChangeSet, (item) => { //assert that conflict occurred on item we just got from local db Assert.IsNotNull(item); Assert.AreEqual(newUserInLocalDb.Email, item.Values["Email"]); Assert.AreEqual(newUserInLocalDb.Name, item.Values["Name"]); Assert.AreEqual(ChangeType.Update, item.ChangeType); //force write in remote store return(ConflictResolution.ForceWrite); }); //now we should have a new version (+1) Assert.IsNotNull(anchorAfterChangesAppliedFromLocalProvider); //and local db changes should be applied to remote db var userChangedInRemoteDb = await remoteDb.Users.AsNoTracking().FirstAsync(_ => _.Email == newUser.Email); Assert.IsNotNull(userChangedInRemoteDb); Assert.AreEqual(newUserInLocalDb.Name, userChangedInRemoteDb.Name); Assert.AreEqual(new DateTime(2019, 1, 1), userChangedInRemoteDb.Created); } }
public SyncAgent(ISyncProvider localSyncProvider, ISyncProvider remoteSyncProvider) { LocalSyncProvider = localSyncProvider ?? throw new ArgumentNullException(nameof(localSyncProvider)); RemoteSyncProvider = remoteSyncProvider ?? throw new ArgumentNullException(nameof(remoteSyncProvider)); }
// // GET: /Series/ public SeriesController(ISyncProvider syncProvider, ISeriesProvider seriesProvider, IEpisodeProvider episodeProvider) { _seriesProvider = seriesProvider; _episodeProvider = episodeProvider; _syncProvider = syncProvider; }
// Token: 0x060010EA RID: 4330 RVA: 0x00045E10 File Offset: 0x00044010 public SyncCalendarResponse Execute(out IFolderSyncState newSyncState, out IList <KeyValuePair <StoreId, LocalizedException> > caughtExceptions) { ExTraceGlobals.SyncCalendarTracer.TraceDebug((long)this.GetHashCode(), "XsoSyncCalendar.Execute: Start"); Stopwatch stopwatch = Stopwatch.StartNew(); caughtExceptions = new List <KeyValuePair <StoreId, LocalizedException> >(); MailboxSyncProviderFactory mailboxSyncProviderFactory = new MailboxSyncProviderFactory(this.session, this.folderId); HashSet <StoreId> syncItemsHashSet = new HashSet <StoreId>(); List <SyncCalendarItemType> updatedItemsList = new List <SyncCalendarItemType>(); List <SyncCalendarItemType> recurrenceMastersWithInstances = new List <SyncCalendarItemType>(); List <SyncCalendarItemType> recurrenceMastersWithoutInstances = new List <SyncCalendarItemType>(); Dictionary <StoreId, SyncCalendarItemType> unchangedRecurrenceMastersWithInstances = new Dictionary <StoreId, SyncCalendarItemType>(); List <StoreId> deletedItemsList = new List <StoreId>(); bool flag = true; CalendarViewQueryResumptionPoint calendarViewQueryResumptionPoint = null; using (ISyncProvider syncProvider = mailboxSyncProviderFactory.CreateSyncProvider(null)) { newSyncState = this.syncState.CreateFolderSyncState(this.folderId, syncProvider); ExDateTime value; if (CalendarSyncState.IsEmpty(this.syncState) || this.syncState.OldWindowEnd == null || this.windowStart >= this.syncState.OldWindowEnd.Value) { ExTraceGlobals.SyncCalendarTracer.TraceDebug((long)this.GetHashCode(), "XsoSyncCalendar.InternalExecute: Requesting catch-up sync state from ICS"); newSyncState.Watermark = syncProvider.GetMaxItemWatermark(newSyncState.Watermark); value = this.windowStart; } else { value = this.syncState.OldWindowEnd.Value; } if (newSyncState.Watermark != null) { int num = this.maxChangesReturned; int num2 = 0; int num3 = 0; if (this.windowEnd > value) { calendarViewQueryResumptionPoint = this.DoQuerySync(syncItemsHashSet, updatedItemsList, recurrenceMastersWithInstances, unchangedRecurrenceMastersWithInstances, value, this.windowEnd, num, caughtExceptions, out num2); flag = !calendarViewQueryResumptionPoint.IsEmpty; num = this.CalculateRemainingItemsCount(num, num2); ExTraceGlobals.SyncCalendarTracer.TraceDebug <int, int, bool>((long)this.GetHashCode(), "XsoSyncCalendar.DoQuerySync added {0} items to the sync response. Remaining Items: {1}; More Available: {2}", num2, num, flag); } if (num != 0) { flag = this.DoIcsSync(syncItemsHashSet, updatedItemsList, recurrenceMastersWithInstances, recurrenceMastersWithoutInstances, unchangedRecurrenceMastersWithInstances, deletedItemsList, newSyncState.Watermark, syncProvider, num, caughtExceptions, out num3); ExTraceGlobals.SyncCalendarTracer.TraceDebug <int, bool>((long)this.GetHashCode(), "XsoSyncCalendar.DoIcsSync added {0} items to the sync response. More Available: {1}", num3, flag); } else { ExTraceGlobals.SyncCalendarTracer.TraceDebug <int, int>((long)this.GetHashCode(), "XsoSyncCalendar; Skipping ICS sync, since we've reached the max items requested (Requested: {0}; Actual: {1}).", this.maxChangesReturned, num2); } ExTraceGlobals.SyncCalendarTracer.TraceDebug <int, int>((long)this.GetHashCode(), "XsoSyncCalendar; Finished fetching items. Total items synced: {0}; Max requested: {1}", num2 + num3, this.maxChangesReturned); } else { flag = false; ExTraceGlobals.SyncCalendarTracer.TraceDebug((long)this.GetHashCode(), "XsoSyncCalendar; Nothing to sync. The specified folder is empty."); } } SyncCalendarResponse result = this.AssembleResponse(flag ? calendarViewQueryResumptionPoint : null, flag ? this.syncState.OldWindowEnd : new ExDateTime?(this.windowEnd), updatedItemsList, recurrenceMastersWithInstances, recurrenceMastersWithoutInstances, unchangedRecurrenceMastersWithInstances, deletedItemsList, !flag); stopwatch.Stop(); ExTraceGlobals.SyncCalendarTracer.TraceDebug((long)this.GetHashCode(), "XsoSyncCalendar.InternalExecute: End " + stopwatch.ElapsedMilliseconds); return(result); }
// Token: 0x060010ED RID: 4333 RVA: 0x00046494 File Offset: 0x00044694 private bool DoIcsSync(HashSet <StoreId> syncItemsHashSet, IList <SyncCalendarItemType> updatedItemsList, IList <SyncCalendarItemType> recurrenceMastersWithInstances, IList <SyncCalendarItemType> recurrenceMastersWithoutInstances, IDictionary <StoreId, SyncCalendarItemType> unchangedRecurrenceMastersWithInstances, IList <StoreId> deletedItemsList, ISyncWatermark watermark, ISyncProvider syncProvider, int maxCount, IList <KeyValuePair <StoreId, LocalizedException> > caughtExceptions, out int addedItems) { ExTraceGlobals.SyncCalendarTracer.TraceDebug((long)this.GetHashCode(), "XsoSyncCalendar.DoIcsSync: Start"); addedItems = 0; int num = (maxCount == 1) ? 1 : ((int)(0.8 * (double)maxCount)); Dictionary <ISyncItemId, ServerManifestEntry> dictionary = new Dictionary <ISyncItemId, ServerManifestEntry>(); bool flag = false; do { ExTraceGlobals.SyncCalendarTracer.TraceDebug <int>((long)this.GetHashCode(), "XsoSyncCalendar.DoIcsSync: Requesting {0} changes from ICS", 100); int numOperations = Math.Min(num - addedItems, 100); flag = syncProvider.GetNewOperations(watermark, null, true, numOperations, null, dictionary); ExTraceGlobals.SyncCalendarTracer.TraceDebug <int>((long)this.GetHashCode(), "XsoSyncCalendar.DoIcsSync: Received {0} entries from ICS", dictionary.Count); foreach (ServerManifestEntry serverManifestEntry in dictionary.Values) { StoreObjectId id = (StoreObjectId)serverManifestEntry.Id.NativeId; switch (serverManifestEntry.ChangeType) { case ChangeType.Add: case ChangeType.Change: addedItems += this.AddNewOrChangedItems(id, updatedItemsList, recurrenceMastersWithInstances, recurrenceMastersWithoutInstances, unchangedRecurrenceMastersWithInstances, deletedItemsList, syncItemsHashSet, caughtExceptions); continue; case ChangeType.Delete: addedItems += this.AddDeletedItem(id, syncItemsHashSet, deletedItemsList); continue; } ExTraceGlobals.SyncCalendarTracer.TraceWarning <ChangeType>((long)this.GetHashCode(), "XsoSyncCalendar.DoIcsSyncs unknown/unexpected sync change type {0}", serverManifestEntry.ChangeType); } }while (flag && num > addedItems); ExTraceGlobals.SyncCalendarTracer.TraceDebug((long)this.GetHashCode(), "XsoSyncCalendar.DoIcsSync: End"); return(flag); }
public void InitializeAllItemsInFilter(ISyncProvider syncProvider) { this.entriesInFilter.Clear(); syncProvider.GetNewOperations(syncProvider.CreateNewWatermark(), null, false, -1, this.filter, this.entriesInFilter); }
private void NotifyFileSystemUpdateFailed(ISyncProvider fileSystem, FileSystemChange change, Exception ex) { if (FileSystemUpdateFailed != null) FileSystemUpdateFailed(this, new FileSystemUpdateFailedEventArgs(fileSystem, change, ex)); }
private void NotifyFileSystemUpdated(ISyncProvider fileSystem, FileSystemChange change) { if (FileSystemUpdated != null) FileSystemUpdated(this, new FileSystemUpdatedEventArgs(fileSystem, change)); }
private string GetSyncProviderId(ISyncProvider provider) { return (provider.GetType().Name).GetMD5().ToString("N"); }
/// <summary> /// Sets the source sync provider. /// </summary> /// <typeparam name="TKey">The type of the key.</typeparam> /// <typeparam name="TItem">The type of the item.</typeparam> /// <param name="syncAgent">The sync agent.</param> /// <param name="syncProvider">The source sync provider of the sync agent.</param> /// <returns></returns> public static ISyncAgent <TKey, TItem> SetSourceProvider <TKey, TItem>(this ISyncAgent <TKey, TItem> syncAgent, ISyncProvider <TItem> syncProvider) { syncAgent.SourceProvider = syncProvider; return(syncAgent); }
/// <summary> /// Sets the destination sync provider. /// </summary> /// <typeparam name="TKey">The type of the key.</typeparam> /// <typeparam name="TItem">The type of the item.</typeparam> /// <param name="syncAgent">The sync agent.</param> /// <param name="syncProvider">The destination sync provider of the sync agent.</param> /// <returns></returns> public static ISyncAgent <TKey, TItem> SetDestinationProvider <TKey, TItem>(this ISyncAgent <TKey, TItem> syncAgent, ISyncProvider <TItem> syncProvider) { syncAgent.DestinationProvider = syncProvider; return(syncAgent); }
private IEnumerable<SyncTarget> GetSyncTargets(ISyncProvider provider, string userId) { var providerId = GetSyncProviderId(provider); return provider.GetSyncTargets().Select(i => new SyncTarget { Name = i.Name, Id = providerId + "-" + i.Id }); }
public TypeConfiguration <U> With(ISyncProvider <U> provider) { TypeProvider.SyncProvider = provider; return(this); }
// Token: 0x060010E4 RID: 4324 public abstract IFolderSyncState CreateFolderSyncState(StoreObjectId folderObjectId, ISyncProvider syncProvider);
private async Task Test2( BlogDbContext localDb, ISyncProvider localSyncProvider, BlogDbContext remoteDb, ISyncProvider remoteSyncProvider) { var localStoreId = await localSyncProvider.GetStoreIdAsync(); var remoteStoreId = await remoteSyncProvider.GetStoreIdAsync(); var newUserLocal = new User() { Email = "*****@*****.**", Name = "user1", Created = new DateTime(2018, 1, 1) }; newUserLocal.Posts.Add(new Post() { Title = "title of post", Content = "content of post", Claps = 2, Stars = 4.5f, Updated = new DateTime(2018, 3, 1) }); localDb.Users.Add(newUserLocal); await localDb.SaveChangesAsync(); //let's apply changes from local db to remote db var localChangeSet = await localSyncProvider.GetChangesAsync(remoteStoreId); Assert.IsNotNull(localChangeSet); Assert.AreEqual(2, localChangeSet.Items.Count); var remoteChangeSet = await remoteSyncProvider.GetChangesAsync(localStoreId); Assert.IsNotNull(remoteChangeSet); Assert.AreEqual(0, remoteChangeSet.Items.Count); var anchorAfterApplyChanges = await remoteSyncProvider.ApplyChangesAsync(localChangeSet); Assert.IsNotNull(anchorAfterApplyChanges); await localSyncProvider.SaveVersionForStoreAsync(remoteStoreId, localChangeSet.SourceAnchor.Version); var changeSetAfterApplyChangesToRemoteDb = await remoteSyncProvider.GetChangesAsync(localStoreId); Assert.IsNotNull(changeSetAfterApplyChangesToRemoteDb); Assert.AreEqual(2, changeSetAfterApplyChangesToRemoteDb.Items.Count); await localSyncProvider.ApplyChangesAsync(changeSetAfterApplyChangesToRemoteDb); await remoteSyncProvider.SaveVersionForStoreAsync(localStoreId, changeSetAfterApplyChangesToRemoteDb.SourceAnchor.Version); newUserLocal.Posts[0].Comments.Add(new Comment() { Content = "my first comment on post", Created = new DateTime(2018, 3, 2) }); newUserLocal.Posts[0].Stars = 4.0f; newUserLocal.Posts[0].Updated = new DateTime(2018, 3, 2); await localDb.SaveChangesAsync(); localChangeSet = await localSyncProvider.GetChangesAsync(remoteStoreId); Assert.IsNotNull(localChangeSet); anchorAfterApplyChanges = await remoteSyncProvider.ApplyChangesAsync(localChangeSet); Assert.IsNotNull(anchorAfterApplyChanges); await localSyncProvider.SaveVersionForStoreAsync(remoteStoreId, localChangeSet.SourceAnchor.Version); var commentAdded = await remoteDb.Comments.FirstOrDefaultAsync(_ => _.Content == "my first comment on post"); Assert.IsNotNull(commentAdded); }
public FirstTimeFolderSync(ISyncProvider syncProvider, IFolderSyncState syncState, ConflictResolutionPolicy policy, bool deferStateModifications) : base(syncProvider, syncState, policy, deferStateModifications) { }
private async Task TestSyncAgentMultipleRecordsOnSameTable( BlogDbContext localDb, ISyncProvider localSyncProvider, BlogDbContext remoteDb, ISyncProvider remoteSyncProvider) { var syncAgent = new SyncAgent(localSyncProvider, remoteSyncProvider); //await syncAgent.InitializeAsync(); await syncAgent.SynchronizeAsync(); //create a user on server var remoteUser = new User() { Email = "*****@*****.**", Name = "user", Created = new DateTime(2018, 1, 1) }; remoteDb.Users.Add(remoteUser); await remoteDb.SaveChangesAsync(); //create a second user on server var remoteUser2 = new User() { Email = "*****@*****.**", Name = "user2", Created = new DateTime(2019, 1, 1) }; remoteDb.Users.Add(remoteUser2); await remoteDb.SaveChangesAsync(); //sync with remote server await syncAgent.SynchronizeAsync(); //verify that new user is stored now locally too var localUser = await localDb.Users.FirstAsync(_ => _.Email == "*****@*****.**"); Assert.AreEqual("user", localUser.Name); Assert.AreEqual(new DateTime(2018, 1, 1), localUser.Created); //verify that new second user is stored now locally too var localUser2 = await localDb.Users.FirstAsync(_ => _.Email == "*****@*****.**"); Assert.AreEqual("user2", localUser2.Name); Assert.AreEqual(new DateTime(2019, 1, 1), localUser2.Created); localUser.Posts.Add(new Post() { Content = "This is first post from user 1", Updated = new DateTime(2019, 1, 1) }); localUser.Posts.Add(new Post() { Content = "This is second post from user 1", Updated = new DateTime(2019, 1, 2) }); localUser2.Posts.Add(new Post() { Content = "This is first post from user 2", Updated = DateTime.Now }); await localDb.SaveChangesAsync(); //create a third user on server var remoteUser3 = new User() { Email = "*****@*****.**", Name = "user3", Created = new DateTime(2019, 1, 1) }; remoteDb.Users.Add(remoteUser3); await remoteDb.SaveChangesAsync(); await syncAgent.SynchronizeAsync(); localDb = localDb.Refresh(); //verify that first user is still stored locally localUser = await localDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**"); Assert.AreEqual("user", localUser.Name); Assert.AreEqual(new DateTime(2018, 1, 1), localUser.Created); //verify that second user is still stored locally localUser2 = await localDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**"); Assert.AreEqual("user2", localUser2.Name); Assert.AreEqual(new DateTime(2019, 1, 1), localUser2.Created); //verify that new third user is stored locally now var localUser3 = await localDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**"); Assert.AreEqual("user3", localUser3.Name); Assert.AreEqual(new DateTime(2019, 1, 1), localUser3.Created); //verify that user posts are still stored locally Assert.AreEqual("This is first post from user 1", localUser.Posts.OrderBy(_ => _.Updated).ToArray()[0].Content); Assert.AreEqual("This is second post from user 1", localUser.Posts.OrderBy(_ => _.Updated).ToArray()[1].Content); Assert.AreEqual("This is first post from user 2", localUser2.Posts.OrderBy(_ => _.Updated).ToArray()[0].Content); remoteDb = remoteDb.Refresh(); //verify that first user is still stored remotely remoteUser = await remoteDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**"); Assert.AreEqual("user", remoteUser.Name); Assert.AreEqual(new DateTime(2018, 1, 1), remoteUser.Created); //verify that second user is still stored remotely remoteUser2 = await remoteDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**"); Assert.AreEqual("user2", remoteUser2.Name); Assert.AreEqual(new DateTime(2019, 1, 1), remoteUser2.Created); //verify that new third user still stored remotely remoteUser3 = await remoteDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**"); Assert.AreEqual("user3", remoteUser3.Name); Assert.AreEqual(new DateTime(2019, 1, 1), remoteUser3.Created); //verify that user posts are still stored remotely Assert.AreEqual("This is first post from user 1", remoteUser.Posts.OrderBy(_ => _.Updated).ToArray()[0].Content); Assert.AreEqual("This is second post from user 1", remoteUser.Posts.OrderBy(_ => _.Updated).ToArray()[1].Content); Assert.AreEqual(1, remoteUser2.Posts.Count); Assert.AreEqual("This is first post from user 2", remoteUser2.Posts.OrderBy(_ => _.Updated).ToArray()[0].Content); //now delete a post locally localDb.Posts.Remove(localUser2.Posts.First()); await localDb.SaveChangesAsync(); await syncAgent.SynchronizeAsync(); remoteDb = remoteDb.Refresh(); remoteUser2 = await remoteDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**"); Assert.AreEqual(0, remoteUser2.Posts.Count); //now delete a post on server remoteDb.Posts.Remove(remoteUser.Posts[0]); await remoteDb.SaveChangesAsync(); await syncAgent.SynchronizeAsync(); localDb = localDb.Refresh(); localUser = await localDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**"); Assert.AreEqual(1, localUser.Posts.Count); remoteUser2.Posts.Add(new Post() { Content = "Post add to remote user while user is delete on local db", Updated = DateTime.Now }); remoteUser2.Name = "edited name"; await remoteDb.SaveChangesAsync(); localDb.Users.Remove(localUser2); await localDb.SaveChangesAsync(); await syncAgent.SynchronizeAsync(conflictResolutionOnLocalStore : ConflictResolution.ForceWrite); remoteDb = remoteDb.Refresh(); localDb = localDb.Refresh(); //ensure that local db updated (local user 2 is present) localUser2 = await localDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**"); localUser2.Posts.Count.ShouldBe(1); localUser2.Posts[0].Content.ShouldBe("Post add to remote user while user is delete on local db"); //ensure that remote db is updated remoteUser2 = await remoteDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**"); remoteUser2.Posts.Count.ShouldBe(1); remoteUser2.Posts[0].Content.ShouldBe("Post add to remote user while user is delete on local db"); }
private async Task TestSyncAgent( BlogDbContext localDb, ISyncProvider localSyncProvider, BlogDbContext remoteDb, ISyncProvider remoteSyncProvider) { var syncAgent = new SyncAgent(localSyncProvider, remoteSyncProvider); await syncAgent.SynchronizeAsync(); //create a user on server var remoteUser = new User() { Email = "*****@*****.**", Name = "user", Created = new DateTime(2018, 1, 1) }; remoteDb.Users.Add(remoteUser); await remoteDb.SaveChangesAsync(); //sync with remote server await syncAgent.SynchronizeAsync(); remoteDb = remoteDb.Refresh(); //discard any cache data in ef //verify that new user is stored now locally too var localUser = await localDb.Users.FirstAsync(_ => _.Email == "*****@*****.**"); Assert.AreEqual("user", localUser.Name); Assert.AreEqual(new DateTime(2018, 1, 1), localUser.Created); //create an article for user locally var localPost = new Post() { Content = "this is my first post", Title = "First Post", Updated = DateTime.Now.Date }; localUser.Posts.Add(localPost); await localDb.SaveChangesAsync(); //sync with remote server await syncAgent.SynchronizeAsync(); remoteDb = remoteDb.Refresh(); //discard any cache data in ef //verify that user on server and locally have the same post remoteUser = await remoteDb.Users.Include(_ => _.Posts).FirstOrDefaultAsync(_ => _.Email == "*****@*****.**"); Assert.AreEqual("user", remoteUser.Name); Assert.AreEqual(new DateTime(2018, 1, 1), remoteUser.Created); Assert.AreEqual(1, remoteUser.Posts.Count); var remotePost = remoteUser.Posts[0]; Assert.AreEqual(localPost.Author.Name, remotePost.Author.Name); Assert.AreEqual(localPost.Content, remotePost.Content); Assert.AreEqual(localPost.Title, remotePost.Title); //now make a change to post content while claps it on server localPost.Content = "this is my my first post edited"; await localDb.SaveChangesAsync(); remotePost.Claps += 1; await remoteDb.SaveChangesAsync(); //then sync await syncAgent.SynchronizeAsync(conflictResolutionOnLocalStore : ConflictResolution.ForceWrite); remoteDb = remoteDb.Refresh(); //discard any cache data in ef //verify that claps is 1 on both server and local stores //content is not changed because we set conflictResolutionOnLocalStore to ConflictResolution.ForceWrite //so server skipped our try to update content while local store forcely write data coming from server remoteUser = await remoteDb.Users.Include(_ => _.Posts).FirstAsync(_ => _.Email == "*****@*****.**"); remotePost = remoteUser.Posts[0]; Assert.AreEqual("user", remotePost.Author.Name); Assert.AreEqual("this is my first post", remotePost.Content); Assert.AreEqual(1, remotePost.Claps); localUser = await localDb.Users.FirstAsync(_ => _.Email == "*****@*****.**"); localPost = localUser.Posts[0]; Assert.AreEqual("user", remotePost.Author.Name); Assert.AreEqual("this is my first post", remotePost.Content); Assert.AreEqual(1, remotePost.Claps); //so to handle this scenario (when a record is often edited on multiple devices) //we should take care of restoring any pending records (posts) locally //for example using a PendingPosts table (not synched) }
private async Task TestSyncAgentWithInitialData( BlogDbContext localDb, ISyncProvider localSyncProvider, BlogDbContext remoteDb, ISyncProvider remoteSyncProvider) { User remoteUser; remoteDb.Users.Add(remoteUser = new User() { Email = "*****@*****.**", Name = "User created before sync", Created = DateTime.Now }); remoteUser.Posts.Add(new Post() { Content = "This is a post created before sync of the client", Title = "Initial post of user 1", Claps = 1, Stars = 10 }); remoteUser.Posts.Add(new Post() { Content = "This is a second post created before sync of the client", Title = "Initial post 2 of user 1", Claps = 2, Stars = 1 }); await remoteDb.SaveChangesAsync(); await remoteSyncProvider.ApplyProvisionAsync(); remoteUser.Posts.Add(new Post() { Content = "This is a third post created before sync of the client but after applying provision to remote db", Title = "Initial post 3 of user 1", Claps = 3, Stars = 1 }); await remoteDb.SaveChangesAsync(); var syncAgent = new SyncAgent(localSyncProvider, remoteSyncProvider); await syncAgent.SynchronizeAsync(); var localUser = await localDb.Users.Include(_ => _.Posts).FirstOrDefaultAsync(_ => _.Email == "*****@*****.**"); localUser.ShouldNotBeNull(); localUser.Email.ShouldBe("*****@*****.**"); localUser.Name.ShouldBe("User created before sync"); var localUserPosts = localUser.Posts.OrderBy(_ => _.Claps).ToList(); localUserPosts.Count().ShouldBe(3); localUserPosts[0].Content.ShouldBe("This is a post created before sync of the client"); localUserPosts[0].Title.ShouldBe("Initial post of user 1"); localUserPosts[0].Claps.ShouldBe(1); localUserPosts[0].Stars.ShouldBe(10); localUserPosts[1].Content.ShouldBe("This is a second post created before sync of the client"); localUserPosts[1].Title.ShouldBe("Initial post 2 of user 1"); localUserPosts[1].Claps.ShouldBe(2); localUserPosts[1].Stars.ShouldBe(1); localUserPosts[2].Content.ShouldBe("This is a third post created before sync of the client but after applying provision to remote db"); localUserPosts[2].Title.ShouldBe("Initial post 3 of user 1"); localUserPosts[2].Claps.ShouldBe(3); localUserPosts[2].Stars.ShouldBe(1); await syncAgent.SynchronizeAsync(); localUser.Posts.Add(new Post() { Content = "Post created on local db after first sync", Title = "Post created on local db", Claps = 4 }); localUserPosts[0].Title = "Post edited on local db"; await localDb.SaveChangesAsync(); await syncAgent.SynchronizeAsync(); remoteDb = remoteDb.Refresh(); var remoteUserPosts = remoteDb.Posts.OrderBy(_ => _.Claps).ToList(); remoteUserPosts.Count().ShouldBe(4); remoteUserPosts[0].Content.ShouldBe("This is a post created before sync of the client"); //even if edited on localdb post that was synched as initial snapshot can't be modified on server remoteUserPosts[0].Title.ShouldBe("Initial post of user 1"); remoteUserPosts[0].Claps.ShouldBe(1); remoteUserPosts[0].Stars.ShouldBe(10); remoteUserPosts[1].Content.ShouldBe("This is a second post created before sync of the client"); remoteUserPosts[1].Title.ShouldBe("Initial post 2 of user 1"); remoteUserPosts[1].Claps.ShouldBe(2); remoteUserPosts[1].Stars.ShouldBe(1); remoteUserPosts[2].Content.ShouldBe("This is a third post created before sync of the client but after applying provision to remote db"); remoteUserPosts[2].Title.ShouldBe("Initial post 3 of user 1"); remoteUserPosts[2].Claps.ShouldBe(3); remoteUserPosts[2].Stars.ShouldBe(1); remoteUserPosts[3].Content.ShouldBe("Post created on local db after first sync"); remoteUserPosts[3].Title.ShouldBe("Post created on local db"); remoteUserPosts[3].Claps.ShouldBe(4); remoteUserPosts[3].Stars.ShouldBe(0); }
private IEnumerable<SyncQualityOption> GetQualityOptions(ISyncProvider provider, SyncTarget target, User user) { var hasQuality = provider as IHasSyncQuality; if (hasQuality != null) { var options = hasQuality.GetQualityOptions(target); if (user != null && !user.Policy.EnableSyncTranscoding) { options = options.Where(i => i.IsOriginalQuality); } return options; } // Default options for providers that don't override return new List<SyncQualityOption> { new SyncQualityOption { Name = "High", Id = "high", IsDefault = true }, new SyncQualityOption { Name = "Medium", Id = "medium" }, new SyncQualityOption { Name = "Low", Id = "low" }, new SyncQualityOption { Name = "Custom", Id = "custom" } }; }
private async Task TestSyncAgentWithUpdatedRemoteDeletedLocal( BlogDbContext localDb, ISyncProvider localSyncProvider, BlogDbContext remoteDb, ISyncProvider remoteSyncProvider) { #region Initialize remote data, sync local and verify User remoteUser; remoteDb.Users.Add(remoteUser = new User() { Email = "*****@*****.**", Name = "User created before sync", Created = DateTime.Now }); remoteUser.Posts.Add(new Post() { Content = "This is a post created before sync of the client", Title = "Initial post of user 1", Claps = 1, Stars = 10 }); remoteUser.Posts.Add(new Post() { Content = "This is a second post created before sync of the client", Title = "Initial post 2 of user 1", Claps = 2, Stars = 1 }); remoteUser.Posts.Add(new Post() { Content = "This is a third post created before sync of the client", Title = "Initial post 3 of user 1", Claps = 3, Stars = 1 }); await remoteDb.SaveChangesAsync(); var syncAgent = new SyncAgent(localSyncProvider, remoteSyncProvider); await syncAgent.SynchronizeAsync(); var localUser = await localDb.Users.Include(_ => _.Posts).FirstOrDefaultAsync(_ => _.Email == "*****@*****.**"); localUser.ShouldNotBeNull(); localUser.Email.ShouldBe("*****@*****.**"); localUser.Name.ShouldBe("User created before sync"); var localUserPosts = localUser.Posts.OrderBy(_ => _.Claps).ToList(); localUserPosts.Count().ShouldBe(3); localUserPosts[0].Content.ShouldBe("This is a post created before sync of the client"); localUserPosts[0].Title.ShouldBe("Initial post of user 1"); localUserPosts[0].Claps.ShouldBe(1); localUserPosts[0].Stars.ShouldBe(10); localUserPosts[1].Content.ShouldBe("This is a second post created before sync of the client"); localUserPosts[1].Title.ShouldBe("Initial post 2 of user 1"); localUserPosts[1].Claps.ShouldBe(2); localUserPosts[1].Stars.ShouldBe(1); localUserPosts[2].Content.ShouldBe("This is a third post created before sync of the client"); localUserPosts[2].Title.ShouldBe("Initial post 3 of user 1"); localUserPosts[2].Claps.ShouldBe(3); localUserPosts[2].Stars.ShouldBe(1); await syncAgent.SynchronizeAsync(); remoteDb = remoteDb.Refresh(); var remoteUserPosts = remoteDb.Posts.OrderBy(_ => _.Claps).ToList(); remoteUserPosts.Count().ShouldBe(3); remoteUserPosts[0].Content.ShouldBe("This is a post created before sync of the client"); //even if edited on localdb post that was synched as initial snapshot can't be modified on server remoteUserPosts[0].Title.ShouldBe("Initial post of user 1"); remoteUserPosts[0].Claps.ShouldBe(1); remoteUserPosts[0].Stars.ShouldBe(10); remoteUserPosts[1].Content.ShouldBe("This is a second post created before sync of the client"); remoteUserPosts[1].Title.ShouldBe("Initial post 2 of user 1"); remoteUserPosts[1].Claps.ShouldBe(2); remoteUserPosts[1].Stars.ShouldBe(1); remoteUserPosts[2].Content.ShouldBe("This is a third post created before sync of the client"); remoteUserPosts[2].Title.ShouldBe("Initial post 3 of user 1"); remoteUserPosts[2].Claps.ShouldBe(3); remoteUserPosts[2].Stars.ShouldBe(1); #endregion #region Remove a local record and verify var postToRemove = localUser.Posts[2]; localDb.Posts.Remove(localUser.Posts[2]); await localDb.SaveChangesAsync(); localUser = await localDb.Users.Include(_ => _.Posts).FirstOrDefaultAsync(_ => _.Email == "*****@*****.**"); Assert.AreEqual(2, localUser.Posts.Count); #endregion #region Update a remote record var remotePost = remoteUser.Posts.First(p => p.Id == postToRemove.Id); remotePost.Content = "Updated remote for test."; remoteDb = remoteDb.Refresh(); remoteDb.Posts.Update(remotePost); await remoteDb.SaveChangesAsync(); remoteUser = await remoteDb.Users.Include(_ => _.Posts).FirstOrDefaultAsync(_ => _.Email == "*****@*****.**"); Assert.AreEqual("Updated remote for test.", remoteUser.Posts.First(p => p.Id == postToRemove.Id).Content); #endregion #region Syncronize and verify the local database has the deleted record //I've delete a post on local database AND updated the same posts on rempte database //SynchronizeAsync() accepts 2 args remoteConflictResolutionFunc and localConflictResolutionFunc //that describe how agent should deal with conflits: //1) remoteConflictResolutionFunc: (itemInConflict) => ConflictResolution.Skip or simply remoteConflictResolution: ConflictResolution.Skip // means that remote database should not apply the delete operation on post coming from local database //2) localConflictResolutionFunc: (itemInConflict) => ConflictResolution.ForceWrite or simply localConflictResolutionFunc: ConflictResolution.ForceWrite // means that local datase should update the local post that was updated from remote db and since the record doesn't exist anymore it actually means insert // the post record again with data coming from server await syncAgent.SynchronizeAsync(); //this above call is the same as this: // await syncAgent.SynchronizeAsync(conflictResolutionOnRemoteStore: ConflictResolution.Skip, conflictResolutionOnLocalStore: ConflictResolution.ForceWrite); //Thanks to Mike Perrenoud I've found that by default await syncAgent.SynchronizeAsync() was instead defaulted to // await syncAgent.SynchronizeAsync(conflictResolutionOnRemoteStore: ConflictResolution.Skip, conflictResolutionOnLocalStore: ConflictResolution.Skip); // causing this test to fail // following code allows to enumerate any item in conflict and take appropriate action for each of them: //await syncAgent.SynchronizeAsync( // remoteConflictResolutionFunc: (itemInConflict) => // { // itemInConflict.ChangeType.ShouldBe(ChangeType.Delete); // itemInConflict.TableName.ShouldBe("Posts"); // itemInConflict.Values["Id"].Value = postToRemove.Id; // return ConflictResolution.Skip; // }, // localConflictResolutionFunc: (itemInConflict) => // { // return ConflictResolution.ForceWrite; // }); localDb = localDb.Refresh(); localUser = await localDb.Users.Include(_ => _.Posts).FirstOrDefaultAsync(_ => _.Email == "*****@*****.**"); Assert.AreEqual(3, localUser.Posts.Count); Assert.AreEqual("Updated remote for test.", localUser.Posts.First(p => p.Id == postToRemove.Id).Content); #endregion }
private IEnumerable<SyncTarget> GetSyncTargets(ISyncProvider provider) { return provider.GetAllSyncTargets().Select(i => new SyncTarget { Name = i.Name, Id = GetSyncTargetId(provider, i) }); }
private async Task TestSyncAgentWithDataRetention( BlogDbContext localDb, ISyncProvider localSyncProvider, BlogDbContext remoteDb, ISyncProvider remoteSyncProvider) { //setup change tracking await remoteSyncProvider.ApplyProvisionAsync(); //create remote data User remoteUser; remoteDb.Users.Add(remoteUser = new User() { Email = "*****@*****.**", Name = "User created before sync", Created = DateTime.Now }); for (int i = 1; i <= 10; i++) { remoteUser.Posts.Add(new Post() { Content = $"Content of Post {i}", Title = $"Post {i}", Claps = 1, Stars = 10 }); } await remoteDb.SaveChangesAsync(); //set data retention -> remove first records in the change tracking table var remoteSyncVersion = await remoteSyncProvider.GetSyncVersionAsync(); remoteSyncVersion.Minimum.ShouldBe(1); remoteSyncVersion.Current.ShouldBe(11);//1 users + 10 posts remoteSyncVersion = await remoteSyncProvider.ApplyRetentionPolicyAsync(4); remoteSyncVersion.Minimum.ShouldBe(4); remoteSyncVersion.Current.ShouldBe(11);// 11 - 4 = 7 posts //local provider is still not synched var localSyncVersion = await localSyncProvider.GetSyncVersionAsync(); localSyncVersion.Minimum.ShouldBe(0); localSyncVersion.Current.ShouldBe(0); //now let's sync var syncAgent = new SyncAgent(localSyncProvider, remoteSyncProvider); await syncAgent.SynchronizeAsync(); localSyncVersion = await localSyncProvider.GetSyncVersionAsync(); localSyncVersion.Minimum.ShouldBe(0); localSyncVersion.Current.ShouldBe(0); (await localDb.Users.ToListAsync()).Count.ShouldBe(1); (await localDb.Posts.ToListAsync()).Count.ShouldBe(10); //now add a new post on server, one on local db than sync remoteDb = remoteDb.Refresh(); remoteUser = await remoteDb.Users.FirstAsync(_ => _.Email == "*****@*****.**"); remoteUser.Posts.Add(new Post() { Content = $"Another post on server", Title = $"New post on server", Claps = 1, Stars = 10 }); await remoteDb.SaveChangesAsync(); var localUser = await localDb.Users.FirstAsync(_ => _.Email == "*****@*****.**"); localUser.Posts.Add(new Post() { Content = $"A post from client", Title = $"New post on client", Claps = 1, Stars = 10 }); await localDb.SaveChangesAsync(); await syncAgent.SynchronizeAsync(); remoteDb = remoteDb.Refresh(); localDb = localDb.Refresh(); (await remoteDb.Users.SingleAsync()).Email.ShouldBe("*****@*****.**"); (await localDb.Users.SingleAsync()).Email.ShouldBe("*****@*****.**"); (await remoteDb.Posts.ToListAsync()).Count.ShouldBe(12); (await localDb.Posts.ToListAsync()).Count.ShouldBe(12); remoteSyncVersion = await remoteSyncProvider.ApplyRetentionPolicyAsync(4); remoteSyncVersion.Minimum.ShouldBe(4); remoteSyncVersion.Current.ShouldBe(13);// +2 posts localSyncVersion = await localSyncProvider.GetSyncVersionAsync(); localSyncVersion.Minimum.ShouldBe(1); localSyncVersion.Current.ShouldBe(2); // +2 posts }
private string GetSyncTargetId(ISyncProvider provider, SyncTarget target) { var hasUniqueId = provider as IHasUniqueTargetIds; if (hasUniqueId != null) { return target.Id; } return target.Id; //var providerId = GetSyncProviderId(provider); //return (providerId + "-" + target.Id).GetMD5().ToString("N"); }
public override IFolderSyncState CreateFolderSyncState(StoreObjectId folderObjectId, ISyncProvider syncProvider) { return(new SyncCalendarFolderSyncState(folderObjectId, syncProvider, base.IcsSyncState)); }
private string GetSyncProviderId(ISyncProvider provider) { return(provider.GetType().Name.GetMD5().ToString("N")); }
private Dictionary <StoreObjectId, string> ProcessCommand(Dictionary <string, CommonNode> oldItems, Folder sourceFolder, MailboxSession mailboxSession) { if (oldItems == null) { throw new ArgumentNullException("items"); } Dictionary <StoreObjectId, string> dictionary = new Dictionary <StoreObjectId, string>(); if (oldItems.Count == 0) { return(dictionary); } GenericDictionaryData <DerivedData <ISyncItemId>, ISyncItemId, ClientManifestEntry> genericDictionaryData = (GenericDictionaryData <DerivedData <ISyncItemId>, ISyncItemId, ClientManifestEntry>) this.syncState[SyncStateProp.CumulativeClientManifest]; if (genericDictionaryData != null) { return(null); } genericDictionaryData = new GenericDictionaryData <DerivedData <ISyncItemId>, ISyncItemId, ClientManifestEntry>(); this.syncState[SyncStateProp.CumulativeClientManifest] = genericDictionaryData; this.clientManifest = genericDictionaryData.Data; this.clientManifest = new Dictionary <ISyncItemId, ClientManifestEntry>(); genericDictionaryData.Data = this.clientManifest; GenericDictionaryData <DerivedData <ISyncItemId>, ISyncItemId, FolderSync.ClientStateInformation> genericDictionaryData2 = (GenericDictionaryData <DerivedData <ISyncItemId>, ISyncItemId, FolderSync.ClientStateInformation>) this.syncState[SyncStateProp.ClientState]; if (genericDictionaryData2 != null) { return(null); } genericDictionaryData2 = new GenericDictionaryData <DerivedData <ISyncItemId>, ISyncItemId, FolderSync.ClientStateInformation>(); this.syncState[SyncStateProp.ClientState] = genericDictionaryData2; genericDictionaryData2.Data = new Dictionary <ISyncItemId, FolderSync.ClientStateInformation>(); MailboxSyncProviderFactory mailboxSyncProviderFactory = new MailboxSyncProviderFactory(mailboxSession, sourceFolder.StoreObjectId); ISyncProvider syncProvider = mailboxSyncProviderFactory.CreateSyncProvider(null); FolderSync folderSync = new FolderSync(syncProvider, this.syncState, ConflictResolutionPolicy.ServerWins, false); using (QueryResult queryResult = sourceFolder.ItemQuery(ItemQueryType.None, null, null, ItemSyncUpgrade.queryColumns)) { bool flag = false; while (!flag && oldItems.Count > 0) { object[][] rows = queryResult.GetRows(10000); flag = (rows.Length == 0); int num = 0; while (num < rows.Length && oldItems.Count > 0) { if (!(rows[num][0] is VersionedId) || !(rows[num][1] is int) || !(rows[num][2] is bool)) { throw new ApplicationException("The data returned from the query is unusable!"); } VersionedId versionedId = (VersionedId)rows[num][0]; StoreObjectId objectId = versionedId.ObjectId; int changeNumber = (int)rows[num][1]; string messageClass = rows[num][3] as string; string oldIdFromNewId = ItemSyncUpgrade.GetOldIdFromNewId(objectId.ProviderLevelItemId); if (oldIdFromNewId == null) { throw new ApplicationException("The new Id is invalid!"); } if (oldItems.ContainsKey(oldIdFromNewId)) { CommonNode commonNode = oldItems[oldIdFromNewId]; oldItems.Remove(oldIdFromNewId); dictionary.Add(objectId, commonNode.ServerId); ISyncItemId syncItemId = MailboxSyncItemId.CreateForNewItem(objectId); FolderSync.ClientStateInformation clientStateInformation = new FolderSync.ClientStateInformation(); clientStateInformation.ClientHasItem = true; genericDictionaryData2.Data[syncItemId] = clientStateInformation; if (!ItemSyncUpgrade.HasChanged(commonNode.VersionId, versionedId)) { bool read; if (commonNode.IsEmail && commonNode.Read != (bool)rows[num][2]) { folderSync.QueueDelayedServerOperation(new ServerManifestEntry(syncItemId) { ChangeType = ChangeType.ReadFlagChange }); read = commonNode.Read; } else { read = (bool)rows[num][2]; } ClientManifestEntry clientManifestEntry = new ClientManifestEntry(syncItemId); clientManifestEntry.Watermark = MailboxSyncWatermark.CreateForSingleItem(); clientManifestEntry.ClientAddId = "TiSyncStateUpgrade"; clientManifestEntry.ChangeType = ChangeType.Add; clientManifestEntry.MessageClass = messageClass; ((MailboxSyncWatermark)clientManifestEntry.Watermark).UpdateWithChangeNumber(changeNumber, read); this.clientManifest.Add(syncItemId, clientManifestEntry); } else { folderSync.QueueDelayedServerOperation(new ServerManifestEntry(syncItemId) { ChangeType = ChangeType.Change, MessageClass = messageClass }); } } num++; } } } if (oldItems.Count > 0) { foreach (KeyValuePair <string, CommonNode> keyValuePair in oldItems) { string key = keyValuePair.Key; CommonNode value = keyValuePair.Value; byte[] bytes = Encoding.Unicode.GetBytes(value.ServerId); StoreObjectId storeObjectId = StoreObjectId.FromProviderSpecificId(bytes, StoreObjectType.Mailbox); dictionary.Add(storeObjectId, value.ServerId); MailboxSyncItemId mailboxSyncItemId = MailboxSyncItemId.CreateForNewItem(storeObjectId); folderSync.QueueDelayedServerOperation(new ServerManifestEntry(mailboxSyncItemId) { ChangeType = ChangeType.Delete }); FolderSync.ClientStateInformation clientStateInformation2 = new FolderSync.ClientStateInformation(); clientStateInformation2.ClientHasItem = true; genericDictionaryData2.Data[mailboxSyncItemId] = clientStateInformation2; } } return(dictionary); }