// 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); }
// 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); }