// This method ensures that we have a valid feed through the formatters. The BodyWriter delegate in WCF
        // seems to not recover from an unhandled exception caused by the formatters and sends out an empty response to the caller.
        // This is a workaround for this issue until we find a better solution.
        private SyncWriter GetSyncWriterWithContents()
        {
            // Get the appropriate SyncWriter instance based on the serialization format.
            SyncWriter oDataWriter = WebUtil.GetSyncWriter(_responseSerializationFormat, _baseUri);

            oDataWriter.StartFeed(_getChangesResponse.IsLastBatch, _getChangesResponse.ServerBlob);

            // Write entities for response.
            foreach (var entity in _getChangesResponse.EntityList)
            {
                // Set the Id and add item with a null tempId.

                entity.ServiceMetadata.Id = WebUtil.GenerateOfflineEntityId(entity);

                oDataWriter.AddItem(entity, null /*tempId*/);
            }

            return(oDataWriter);
        }
Example #2
0
        // This method ensures that we have a valid feed through the formatters. The BodyWriter delegate in WCF
        // seems to not recover from an unhandled exception caused by the formatters and sends out an empty response to the caller.
        // This is a workaround for this issue until we find a better solution.
        private SyncWriter GetSyncWriterWithContents()
        {
            var conflictEntryKeys = new List <string>();
            var errorEntryKeys    = new List <string>();
            var primaryKeyToIncomingEntitiesMapping = new Dictionary <string, IOfflineEntity>();

            // Save the mapping between entity PK string -> entity
            foreach (var entity in _incomingEntities)
            {
                string primaryKey = ReflectionUtility.GetPrimaryKeyString(entity);
                if (primaryKeyToIncomingEntitiesMapping.ContainsKey(primaryKey))
                {
                    throw SyncServiceException.CreateInternalServerError(Strings.MultipleEntriesWithSamePrimaryKeyInIncomingRequest);
                }

                primaryKeyToIncomingEntitiesMapping.Add(primaryKey, entity);
            }

            if (_rejectedEntities != null)
            {
                foreach (var entity in _rejectedEntities.Keys)
                {
                    string primaryKey = ReflectionUtility.GetPrimaryKeyString(entity);
                    if (primaryKeyToIncomingEntitiesMapping.ContainsKey(primaryKey))
                    {
                        throw SyncServiceException.CreateInternalServerError(Strings.MultipleEntriesWithSamePrimaryKeyInIncomingRequest);
                    }

                    primaryKeyToIncomingEntitiesMapping.Add(primaryKey, entity);
                }
            }

            // Get the appropriate SyncWriter instance based on the serialization format.
            var oDataWriter = WebUtil.GetSyncWriter(_responseSerializationFormat, _baseUri);

            oDataWriter.StartFeed(_applyChangesResponse.IsLastBatch, _applyChangesResponse.ServerBlob);

            // Write conflict entities.
            foreach (var entity in _applyChangesResponse.Conflicts)
            {
                // Add the primary key string to the conflictEntryKey list.
                // The primary keys are the same for both Live and Losing entities.
                conflictEntryKeys.Add(ReflectionUtility.GetPrimaryKeyString(entity.LiveEntity));

                string tempId;

                // If the client change lost, then we need to set the Id property
                // only if the property was not null/empty in the incoming request.
                string entityId = WebUtil.GenerateOfflineEntityId(entity.LiveEntity);

                // Set the Id property of the Live entity (server's copy).
                entity.LiveEntity.ServiceMetadata.Id = entityId;

                // Set the Id property of the Losing entity to the incoming entity's Id value
                entity.LosingEntity.ServiceMetadata.Id = entityId;

                // get the original tempId. Null value is ok.
                _idToTempIdMapping.TryGetValue(entityId, out tempId);

                if (entity.Resolution == SyncConflictResolution.ServerWins)
                {
                    // The losing entity is the client's copy.

                    // When resolution is ServerWins, we only need to set the losing change tempId.
                    oDataWriter.AddConflictItem(entity.LiveEntity, null /*tempId*/, entity.LosingEntity, tempId, entity.Resolution);
                }
                // If the client change won, then just set the Id property since an insert would have succeeded.
                else
                {
                    // When resolution is ClientWins, we only need to set the LiveEntity tempId.
                    oDataWriter.AddConflictItem(entity.LiveEntity, tempId, entity.LosingEntity, null /* tempId */, entity.Resolution);
                }
            }

            // Write error entities.
            foreach (var syncError in _applyChangesResponse.Errors)
            {
                Debug.Assert(null != syncError.LiveEntity);
                Debug.Assert(null != syncError.ErrorEntity);

                string entityId = WebUtil.GenerateOfflineEntityId(syncError.LiveEntity);

                // Set the Id for Live and Losing entity.
                syncError.LiveEntity.ServiceMetadata.Id  = entityId;
                syncError.ErrorEntity.ServiceMetadata.Id = entityId;

                string primaryKeyString = ReflectionUtility.GetPrimaryKeyString(syncError.ErrorEntity);

                // Add the string to the error key list.
                errorEntryKeys.Add(primaryKeyString);

                string tempId;

                _idToTempIdMapping.TryGetValue(entityId, out tempId);

                oDataWriter.AddErrorItem(syncError.LiveEntity, syncError.ErrorEntity, tempId, syncError.Description);
            }

            // Write all the inserted records here by iterating over the _incomingNewInsertEntities list
            foreach (var entity in _incomingNewInsertEntities)
            {
                string entityTempId;

                // Get the tempId of the entity.
                _idToTempIdMapping.TryGetValue(WebUtil.GenerateOfflineEntityId(entity), out entityTempId);

                // Write the output to the SyncWriter.
                oDataWriter.AddItem(entity, entityTempId);
            }

            return(oDataWriter);
        }