public async Task <(SyncContext, ChangesApplied)> ApplyChangesAsync(SyncContext ctx, MessageApplyChanges message)
 => await this.LocalProvider.ApplyChangesAsync(ctx, message);
        /// <summary>
        /// Send changes to server
        /// </summary>
        public async Task <(SyncContext, ChangesApplied)> ApplyChangesAsync(SyncContext context, MessageApplyChanges message)
        {
            if (message.Changes == null || message.Changes.BatchPartsInfo.Count == 0)
            {
                return(context, new ChangesApplied());
            }

            SyncContext    syncContext    = null;
            ChangesApplied changesApplied = null;

            // Foreach part, will have to send them to the remote
            // once finished, return context
            foreach (var bpi in message.Changes.BatchPartsInfo.OrderBy(bpi => bpi.Index))
            {
                var applyChanges = new HttpMessageApplyChanges
                {
                    FromScope           = message.FromScope,
                    Schema              = new DmSetSurrogate(message.Schema),
                    Policy              = message.Policy,
                    UseBulkOperations   = message.UseBulkOperations,
                    ScopeInfoTableName  = message.ScopeInfoTableName,
                    SerializationFormat = message.SerializationFormat
                };

                HttpMessage httpMessage = new HttpMessage
                {
                    Step        = HttpStep.ApplyChanges,
                    SyncContext = context,
                    Content     = applyChanges
                };

                // If BPI is InMempory, no need to deserialize from disk
                // Set already contained in part.Set
                if (!message.Changes.InMemory)
                {
                    // get the batch
                    var partBatch = bpi.GetBatch();

                    // get the surrogate dmSet
                    if (partBatch != null)
                    {
                        applyChanges.Set = partBatch.DmSetSurrogate;
                    }
                }
                else if (bpi.Set != null)
                {
                    applyChanges.Set = new DmSetSurrogate(bpi.Set);
                }

                if (applyChanges.Set == null || applyChanges.Set.Tables == null)
                {
                    throw new ArgumentException("No changes to upload found.");
                }

                // no need to send filename
                applyChanges.BatchPartInfo = new BatchPartInfo
                {
                    FileName    = null,
                    Index       = bpi.Index,
                    IsLastBatch = bpi.IsLastBatch,
                    Tables      = bpi.Tables
                };
                applyChanges.InMemory   = message.Changes.InMemory;
                applyChanges.BatchIndex = bpi.Index;

                //Post request and get response
                var httpMessageResponse = await this.httpRequestHandler.ProcessRequest(httpMessage, message.SerializationFormat, cancellationToken);

                // Clear surrogate
                applyChanges.Set.Dispose();
                applyChanges.Set = null;

                if (httpMessageResponse == null)
                {
                    throw new Exception("Can't have an empty body");
                }

                HttpMessageApplyChanges httpMessageContent;
                if (httpMessageResponse.Content is HttpMessageApplyChanges)
                {
                    httpMessageContent = httpMessageResponse.Content as HttpMessageApplyChanges;
                }
                else
                {
                    httpMessageContent = (httpMessageResponse.Content as JObject).ToObject <HttpMessageApplyChanges>();
                }

                syncContext    = httpMessageResponse.SyncContext;
                changesApplied = httpMessageContent.ChangesApplied;
            }

            return(syncContext, changesApplied);
        }