Esempio n. 1
0
        /// <summary>
        /// OfflineSyncProvider method implementation called when a change set returned from GetChangeSet has been
        /// successfully uploaded.
        /// </summary>
        /// <param name="state">The unique identifier passed in to the GetChangeSet call.</param>
        /// <param name="response">ChangeSetResponse that contains an updated server blob and any conflicts or errors that
        /// happened on the service.</param>
        public override async Task OnChangeSetUploaded(Guid state, ChangeSetResponse response)
        {
            ThrowIfDisposed();

            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            if (!syncActive)
            {
                throw new InvalidOperationException("OnChangeSetUploaded cannot be called without calling BeginSession");
            }

            if (response.Error == null)
            {
                IEnumerable <OfflineEntity> updatedItems =
                    response.UpdatedItems.Cast <OfflineEntity>();

                // Notify the disk management that changes uploaded successfully.
                IEnumerable <Conflict> conflicts =
                    await StorageHandler.UploadSucceeded(state, response.ServerBlob, response.Conflicts, updatedItems);

                // Update the in-memory representation.
                cacheData.AddUploadChanges(response.ServerBlob, conflicts, updatedItems, this);
            }
            else
            {
                StorageHandler.UploadFailed(state);
            }
        }
        public async Task <bool> Handle(ChangeSetRequest message, IOutputPort <ChangeSetResponse> outputPort)
        {
            ChangeSetResponse response = new ChangeSetResponse(message);

            try
            {
                CRUDContext <TService> context = new CRUDContext <TService>(message, response, (TService)_service, _serviceContainer);
                context.Properties.Add(CRUDContext <TService> .CHANGE_METHODS_KEY, _serviceMethods);

                await _pipeline(context);
            }
            catch (Exception ex)
            {
                if (ex is TargetInvocationException)
                {
                    ex = ex.InnerException;
                }

                string err = _serviceMethods.OnError(ex);
                response.error = new ErrorInfo(err, ex.GetType().Name);
            }

            outputPort.Handle(response);

            return(response.error == null);
        }
Esempio n. 3
0
 public CRUDContext(
     ChangeSetRequest request,
     ChangeSetResponse response,
     TService service,
     IServiceContainer <TService> serviceContainer)
 {
     _ExceptionInfo   = null;
     Request          = request;
     Response         = response;
     Service          = service;
     ServiceContainer = serviceContainer;
     Properties       = new Dictionary <string, object>();
 }
Esempio n. 4
0
        /// <summary>
        /// Retrieve the status of a change set.
        /// </summary>
        /// <param name="changeSetID">The Id of the change set.</param>
        /// <returns>The change set status response.</returns>
        private async Task <ChangeSetResponse> GetChangeSetStatus(string changeSetID)
        {
            var getChangeSetStatusRequest = new GetChangeSetStatusRequest
            {
                ChangeSetId = changeSetID,
            };

            Console.Write($"Getting status of change set {changeSetID}... ");

            ChangeSetResponse changeSetStatusResponse = await this.orgClient.GetChangeSetStatusAsync(getChangeSetStatusRequest).ConfigureAwait(false);

            Console.WriteLine(changeSetStatusResponse.Status);

            return(changeSetStatusResponse);
        }
Esempio n. 5
0
        public CacheRequestResult(Guid id, ChangeSetResponse response, int uploadCount, Exception error, object state)
        {
            this.ChangeSetResponse = response;
            this.Error = error;
            this.State = state;
            this.Id = id;
            this.BatchUploadCount = (uint)uploadCount;

            // Check that error is carried over to the response
            if (this.Error == null) return;

            if (this.ChangeSetResponse == null)
                this.ChangeSetResponse = new ChangeSetResponse();

            this.ChangeSetResponse.Error = this.Error;
        }
Esempio n. 6
0
        /// <summary>
        /// OfflineSyncProvider method implementation called when a change set returned from GetChangeSet has been
        /// successfully uploaded.
        /// </summary>
        /// <param name="state">The unique identifier passed in to the GetChangeSet call.</param>
        /// <param name="response">ChangeSetResponse that contains an updated server blob and any conflicts or errors that
        /// happened on the service.</param>
        public override void OnChangeSetUploaded(Guid state, ChangeSetResponse response)
        {
            ThrowIfDisposed();

            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            if (!_syncActive)
            {
                throw new InvalidOperationException("OnChangeSetUploaded cannot be called without calling BeginSession");
            }

            if (response.Error == null)
            {
                //Sergei Polevikov
                //IEnumerable<IsolatedStorageOfflineEntity> updatedItems = response.UpdatedItems.Cast<IsolatedStorageOfflineEntity>();
                List <IsolatedStorageOfflineEntity> updatedItems = new List <IsolatedStorageOfflineEntity>();
                foreach (IsolatedStorageOfflineEntity updatedItem in response.UpdatedItems)
                {
                    updatedItems.Add(updatedItem);
                }
                //end

                // Notify the disk management that changes uploaded successfully.
                IEnumerable <Conflict> conflicts = _storageHandler.UploadSucceeded(state, response.ServerBlob, response.Conflicts, updatedItems);

                // Update the in-memory representation.
                _cacheData.AddUploadChanges(response.ServerBlob, conflicts, updatedItems, this);
            }
            else
            {
                _storageHandler.UploadFailed(state);
            }
        }
Esempio n. 7
0
        public async Task <ActionResult> Save([FromBody] ChangeSetRequest changeSet)
        {
            ChangeSetResponse res = await DomainService.ServiceApplyChangeSet(changeSet);

            return(new ChunkedResult <ChangeSetResponse>(res, DomainService.Serializer));
        }
Esempio n. 8
0
 /// <summary>
 /// OnChangeSetUploaded, fired when changeset is uploaded
 /// </summary>
 /// <param name="state"></param>
 /// <param name="response"></param>
 public abstract Task OnChangeSetUploaded(Guid state, ChangeSetResponse response);
        public override void OnChangeSetUploaded(Guid state, ChangeSetResponse response)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            if (response.Error != null)
            {
                throw response.Error;
            }
            this.OnSyncProgress(new SyncProgressEventArgs("Upload finished,mark local entities as uploaded..."));

            siaqodb.StartBulkInsert(CacheController.ControllerBehavior.KnownTypes.ToArray());
            try
            {
                if (null != response.UpdatedItems && 0 != response.UpdatedItems.Count)
                {
                    List <string> IdsWithError = new List <string>();
                    foreach (Conflict cf in response.Conflicts)
                    {
                        if (cf is SyncError)
                        {
                            IdsWithError.Add(cf.LiveEntity.ServiceMetadata.Id);
                        }
                    }

                    foreach (var item in response.UpdatedItems)
                    {
                        if (IdsWithError.Contains(item.ServiceMetadata.Id))
                        {
                            continue;
                        }
                        var offlineEntity = (SiaqodbOfflineEntity)item;
                        offlineEntity.IsDirty     = false;
                        offlineEntity.IsTombstone = false;
                        this.SaveEntityByPK(offlineEntity);
                    }
                }

                if (response.Conflicts != null && response.Conflicts.Count > 0)
                {
                    ConflictsEventArgs ceArgs = new ConflictsEventArgs(response.Conflicts);
                    this.OnConflictOccur(ceArgs);
                    if (!ceArgs.CancelResolvingConflicts)
                    {
                        foreach (var conflict in response.Conflicts)
                        {
                            if (conflict is SyncError)
                            {
                                continue;
                            }
                            var offlineEntity = (SiaqodbOfflineEntity)conflict.LiveEntity;
                            offlineEntity.IsDirty     = false;
                            offlineEntity.IsTombstone = false;
                            this.SaveEntity(offlineEntity);
                        }
                    }
                }

                ICollection <IOfflineEntity> changesJustUploaded = this.currentChanges[state];
                foreach (IOfflineEntity enI in changesJustUploaded)
                {
                    SiaqodbOfflineEntity en = enI as SiaqodbOfflineEntity;
                    //check if we did not updated above
                    if (null != response.UpdatedItems && 0 != response.UpdatedItems.Count)
                    {
                        bool existsUpdated = false;
                        foreach (var item in response.UpdatedItems)
                        {
                            var offlineEntity = (SiaqodbOfflineEntity)item;
                            if (EntitiesEqualByPK(offlineEntity, en))
                            {
                                existsUpdated = true;
                            }
                        }
                        if (existsUpdated)
                        {
                            continue;
                        }
                    }
                    if (response.Conflicts != null && response.Conflicts.Count > 0)
                    {
                        bool existsUpdated = false;
                        foreach (var conflict in response.Conflicts)
                        {
                            var offlineEntity = (SiaqodbOfflineEntity)conflict.LiveEntity;
                            if (EntitiesEqualByPK(offlineEntity, en))
                            {
                                existsUpdated = true;
                            }
                        }
                        if (existsUpdated)
                        {
                            continue;
                        }
                    }

                    if (en.IsTombstone)
                    {
                        en.IsDirty     = false;
                        en.IsTombstone = false;
                        //reset flags first
                        siaqodb.StoreObjectBase(en);

                        siaqodb.DeleteBase(en);
                    }
                    else
                    {
                        en.IsDirty = false;
                        siaqodb.StoreObjectBase(en);
                    }
                }
            }
            finally
            {
                siaqodb.EndBulkInsert(CacheController.ControllerBehavior.KnownTypes.ToArray());
                siaqodb.Flush();
            }

            this.SaveAnchor(response.ServerBlob);

            this.OnSyncProgress(new SyncProgressEventArgs("Downloading changes from server..."));
            currentChanges.Remove(state);
        }
Esempio n. 10
0
        /// <summary>
        /// OfflineSyncProvider method implementation called when a change set returned from GetChangeSet has been
        /// successfully uploaded.
        /// </summary>
        /// <param name="state">The unique identifier passed in to the GetChangeSet call.</param>
        /// <param name="response">ChangeSetResponse that contains an updated server blob and any conflicts or errors that
        /// happened on the service.</param>
        public override void OnChangeSetUploaded(Guid state, ChangeSetResponse response)
        {
            if (null == response)
            {
                throw new ArgumentNullException("response");
            }

            if (null != response.Error)
            {
                throw new Exception("Exception during sync!");
            }

            var storageHandler = new SqlCeStorageHandler();

            if (null != response.UpdatedItems && 0 != response.UpdatedItems.Count)
            {
                foreach (var item in response.UpdatedItems)
                {
                    var offlineEntity = (SqlCeOfflineEntity)item;
                    storageHandler.ApplyItem(offlineEntity);
                }
            }

            if (null != response.Conflicts && 0 != response.Conflicts.Count)
            {
                foreach (var conflict in response.Conflicts)
                {
                    // We have an conflict so apply the LiveEntity
                    var liveEntity = (SqlCeOfflineEntity)conflict.LiveEntity;

                    // For a SyncError, which resulted from a client insert, the winning item may be a tombstone version
                    // of the client entity. In this case, the ServiceMetadata.Id property of the LiveEntity will be null.
                    // We need to lookup the item using primary keys in order to update it.
                    if (conflict.GetType() == typeof(SyncError))
                    {
                        var errorEntity = ((SyncError)conflict).ErrorEntity;

                        if (!liveEntity.ServiceMetadata.IsTombstone)
                        {
                            // If the live entity is not a tombstone, then we just need to update the entity.
                            storageHandler.ApplyItem(liveEntity);
                        }
                        else
                        {
                            // At this point, the LiveEntity is a tombstone and does not have primary key info.

                            // If the live entity is a tombstone, then delete the item by looking up the primary key
                            // from the error entity.
                            // The error entity in this case will have both Id and the primary keys.
                            errorEntity.ServiceMetadata.IsTombstone = true;
                            errorEntity.ServiceMetadata.Id          = null;
                            storageHandler.ApplyItem((SqlCeOfflineEntity)errorEntity);
                        }
                    }
                    else
                    {
                        storageHandler.ApplyItem(liveEntity);
                    }
                }
            }

            // Clear all the isdirty flags and delete all rows with IsTombstone = true
            storageHandler.ResetDirtyAndDeleteTombstones();

            storageHandler.SaveAnchor(response.ServerBlob);
        }
Esempio n. 11
0
        /// <summary>
        /// Demonstrate the full asynchronous change set workflow (create change set, upload contents, check results).
        /// </summary>
        /// <param name="parentTree">The tree to which to apply the change set.</param>
        /// <returns>Does not return anything.</returns>
        private async Task RunAsyncChangeSetWorkflow(Tree parentTree)
        {
            if (parentTree != null)
            {
                // Create an asynchronous change set (declare intention to upload changes)
                ChangeSetResponseInitiated createAsyncChangesSetResponse = await this.CreateAsyncChangeset(parentTree).ConfigureAwait(false);

                if (string.Compare(createAsyncChangesSetResponse.Status, "WaitingUpload", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    // Upload the change set contents asynchronously
                    await this.UploadChangeSetContents(createAsyncChangesSetResponse.UploadURL).ConfigureAwait(false);

                    // Wait until the change set has finished processing.
                    // Use a change set status checking algorithm with exponential backoff an jitter
                    // to reduce the load on the server and increase chance of success.
                    const int    CheckhangeSetStatusInitialInterval   = 2000;
                    const int    CheckChangeSetstatusMaxInterval      = 30000;
                    const double CheckChangeSetIntervalIncreaseFactor = 2.0;
                    const int    CheckChangeSetMaxJitter = 1000;
                    const int    ChangeSetTimeOut        = 90000;

                    int               checkChangeSetStatusInterval = CheckhangeSetStatusInitialInterval;
                    Random            random = new Random();
                    ChangeSetResponse getChangeSetStatusResponse = null;
                    Stopwatch         watch = Stopwatch.StartNew();

                    do
                    {
                        Console.WriteLine($"Waiting {(int)checkChangeSetStatusInterval/1000.0} sec...");
                        Thread.Sleep(checkChangeSetStatusInterval);

                        getChangeSetStatusResponse = await this.GetChangeSetStatus(createAsyncChangesSetResponse.Id).ConfigureAwait(false);

                        checkChangeSetStatusInterval = Math.Min((int)(checkChangeSetStatusInterval * CheckChangeSetIntervalIncreaseFactor), CheckChangeSetstatusMaxInterval) + random.Next(CheckChangeSetMaxJitter);
                    }while ((string.Compare(getChangeSetStatusResponse.Status, "WaitingUpload", StringComparison.OrdinalIgnoreCase) == 0 ||
                             string.Compare(getChangeSetStatusResponse.Status, "Queued", StringComparison.OrdinalIgnoreCase) == 0 ||
                             string.Compare(getChangeSetStatusResponse.Status, "Processing", StringComparison.OrdinalIgnoreCase) == 0) &&
                            watch.ElapsedMilliseconds <= ChangeSetTimeOut);

                    Console.WriteLine($"Change set status: {getChangeSetStatusResponse.Status}");

                    if (string.Compare(getChangeSetStatusResponse.Status, "Done", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        // Get the change set results
                        if (!string.IsNullOrEmpty(getChangeSetStatusResponse.ResultsURL))
                        {
                            Console.WriteLine("Change set results: ");
                            await this.changeSetClient.GetNDJsonAsync <Node>(getChangeSetStatusResponse.ResultsURL, this.PrintNodes).ConfigureAwait(false);
                        }

                        // Get the change set errors
                        if (!string.IsNullOrEmpty(getChangeSetStatusResponse.ErrorsURL))
                        {
                            Console.WriteLine("Change set errors: ");
                            await this.changeSetClient.GetNDJsonAsync(
                                getChangeSetStatusResponse.ErrorsURL,
                                (IEnumerable <UnprocessedNode> unprocessedNodesChunk) =>
                            {
                                if (unprocessedNodesChunk != null)
                                {
                                    foreach (var unprocessedNode in unprocessedNodesChunk)
                                    {
                                        Console.Write($" {unprocessedNode.Code} {unprocessedNode.Message}");
                                        if (unprocessedNode.Item != null)
                                        {
                                            Console.Write($" {unprocessedNode.Item.Id} {unprocessedNode.Item.Name}");
                                        }
                                    }

                                    Console.WriteLine();
                                }
                            }).ConfigureAwait(false);
                        }
                    }
                }

                Console.WriteLine();
            }
        }
Esempio n. 12
0
        /// <summary>
        /// SQLiteContext method implementation called when a change set returned from GetChangeSet has been
        /// successfully uploaded.
        /// </summary>
        /// <param name="state">The unique identifier passed in to the GetChangeSet call.</param>
        /// <param name="response">ChangeSetResponse that contains an updated server blob and any conflicts or errors that
        /// happened on the service.</param>
        public override async Task OnChangeSetUploaded(Guid state, ChangeSetResponse response)
        {
            await Task.Run(() =>
            {
                ThrowIfDisposed();

                if (response == null)
                {
                    throw new ArgumentNullException("response");
                }

                if (!syncActive)
                {
                    throw new InvalidOperationException("OnChangeSetUploaded cannot be called without calling BeginSession");
                }

                if (response.Error == null)
                {
                    IEnumerable <SQLiteOfflineEntity> conflictEntities = null;
                    IEnumerable <SQLiteOfflineEntity> updatedItems     = null;

                    // Get conflicts and notify user
                    if (response.Conflicts != null)
                    {
                        // This approach assumes that there are not duplicates between the conflicts and the updated entities (there shouldn't be)
                        conflictEntities = (from c in response.Conflicts
                                            select(SQLiteOfflineEntity) c.LiveEntity);

                        this.Conflicts = response.Conflicts;
                    }

                    // Get the Updated Items from Server
                    // A read only collection of Insert entities uploaded by clients that have been issued
                    // permanent Id's by the service
                    if (response.UpdatedItems != null && response.UpdatedItems.Count > 0)
                    {
                        updatedItems = response.UpdatedItems.Cast <SQLiteOfflineEntity>();
                    }

                    IEnumerable <SQLiteOfflineEntity> allItems = updatedItems ?? new List <SQLiteOfflineEntity>();

                    // Add conflict entities
                    if (conflictEntities != null)
                    {
                        allItems = allItems.Concat(conflictEntities);
                    }

                    this.Manager.SaveDownloadedChanges(allItems);


                    // Notify the disk management that changes uploaded successfully.
                    // Update all Entities and Set IsDirty = 0
                    // Remvove tarcking tombstone
                    Manager.UploadSucceeded(state);


                    // Set the new Anchor
                    this.Configuration.AnchorBlob = response.ServerBlob;
                }
            });
        }
        /// <summary>
        /// OfflineSyncProvider method implementation called when a change set returned from GetChangeSet has been
        /// successfully uploaded.
        /// </summary>
        /// <param name="state">The unique identifier passed in to the GetChangeSet call.</param>
        /// <param name="response">ChangeSetResponse that contains an updated server blob and any conflicts or errors that
        /// happened on the service.</param>
        public override void OnChangeSetUploaded(Guid state, ChangeSetResponse response)
        {
            ThrowIfDisposed();

            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            if (!_syncActive)
            {
                throw new InvalidOperationException("OnChangeSetUploaded cannot be called without calling BeginSession");
            }

            if (response.Error == null)
            {
                //Sergei Polevikov
                //IEnumerable<IsolatedStorageOfflineEntity> updatedItems = response.UpdatedItems.Cast<IsolatedStorageOfflineEntity>();
                List<IsolatedStorageOfflineEntity> updatedItems = new List<IsolatedStorageOfflineEntity>();
                foreach (IsolatedStorageOfflineEntity updatedItem in response.UpdatedItems)
                {
                    updatedItems.Add(updatedItem);
                }
                //end

                // Notify the disk management that changes uploaded successfully.
                IEnumerable<Conflict> conflicts = _storageHandler.UploadSucceeded(state, response.ServerBlob, response.Conflicts, updatedItems);

                // Update the in-memory representation.
                _cacheData.AddUploadChanges(response.ServerBlob, conflicts, updatedItems, this);
            }
            else
            {
                _storageHandler.UploadFailed(state);
            }
        }
Esempio n. 14
0
        public async Task <ActionResult> Save([ServiceParamsBinder] ChangeSetRequest changeSet)
        {
            ChangeSetResponse response = await DomainService.ServiceApplyChangeSet(changeSet);

            return(new ChunkedResult <ChangeSetResponse>(response, Serializer));
        }