GetEstimatedChangesCountAsync(ClientScopeInfo clientScopeInfo, SyncParameters parameters = default, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) { var context = new SyncContext(Guid.NewGuid(), clientScopeInfo.Name); if (parameters != null) { context.Parameters = parameters; } SyncSet schema; ServerScopeInfo serverScopeInfo; // Need the server scope (context, serverScopeInfo) = await this.InternalGetServerScopeInfoAsync(context, clientScopeInfo.Setup, false, connection, transaction, cancellationToken, progress).ConfigureAwait(false); schema = serverScopeInfo.Schema; schema.EnsureSchema(); clientScopeInfo.Schema = schema; clientScopeInfo.Setup = serverScopeInfo.Setup; clientScopeInfo.Version = serverScopeInfo.Version; // generate a message to send var changesToSend = new HttpMessageSendChangesRequest(context, clientScopeInfo) { Changes = null, IsLastBatch = true, BatchIndex = 0, BatchCount = 0 }; var serializer = this.SerializerFactory.GetSerializer <HttpMessageSendChangesRequest>(); var binaryData = await serializer.SerializeAsync(changesToSend); // Raise progress for sending request and waiting server response await this.InterceptAsync(new HttpGettingServerChangesRequestArgs(0, 0, context, this.GetServiceHost()), progress, cancellationToken).ConfigureAwait(false); // response var response = await this.httpRequestHandler.ProcessRequestAsync (this.HttpClient, context, this.ServiceUri, binaryData, HttpStep.GetEstimatedChangesCount, this.SerializerFactory, this.Converter, this.Options.BatchSize, this.SyncPolicy, cancellationToken, progress).ConfigureAwait(false); HttpMessageSendChangesResponse summaryResponseContent = null; using (var streamResponse = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) { var responseSerializer = this.SerializerFactory.GetSerializer <HttpMessageSendChangesResponse>(); if (streamResponse.CanRead) { summaryResponseContent = await responseSerializer.DeserializeAsync(streamResponse); } } if (summaryResponseContent == null) { throw new Exception("Summary can't be null"); } // generate the new scope item this.CompleteTime = DateTime.UtcNow; return(new (summaryResponseContent.RemoteClientTimestamp, null, summaryResponseContent.ServerChangesSelected)); }
/// <summary> /// Get changes from /// </summary> internal async Task <HttpMessageSendChangesResponse> ApplyThenGetChangesAsync(HttpMessageSendChangesRequest httpMessage, SessionCache sessionCache, int clientBatchSize, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) { // Overriding batch size options value, coming from client // having changes from server in batch size or not is decided by the client. // Basically this options is not used on the server, since it's always overriden by the client this.Options.BatchSize = clientBatchSize; // Get if we need to serialize data or making everything in memory var clientWorkInMemory = clientBatchSize == 0; // Get context from request message var ctx = httpMessage.SyncContext; // Set the context coming from the client this.SetContext(ctx); // Check schema. // If client has stored the schema, the EnsureScope will not be called on server. if (this.Schema == null || !this.Schema.HasTables || !this.Schema.HasColumns) { var serverScopeInfo = await this.EnsureSchemaAsync(cancellationToken, progress).ConfigureAwait(false); this.Schema = serverScopeInfo.Schema; this.Schema.EnsureSchema(); } // ------------------------------------------------------------ // FIRST STEP : receive client changes // ------------------------------------------------------------ // We are receiving changes from client // BatchInfo containing all BatchPartInfo objects // Retrieve batchinfo instance if exists // Get batch info from session cache if exists, otherwise create it if (sessionCache.ClientBatchInfo == null) { sessionCache.ClientBatchInfo = new BatchInfo(clientWorkInMemory, Schema, this.Options.BatchDirectory); } // create the in memory changes set var changesSet = new SyncSet(); foreach (var table in httpMessage.Changes.Tables) { DbSyncAdapter.CreateChangesTable(Schema.Tables[table.TableName, table.SchemaName], changesSet); } changesSet.ImportContainerSet(httpMessage.Changes, false); // If client has made a conversion on each line, apply the reverse side of it if (this.ClientConverter != null && changesSet.HasRows) { AfterDeserializedRows(changesSet, this.ClientConverter); } // add changes to the batch info await sessionCache.ClientBatchInfo.AddChangesAsync(changesSet, httpMessage.BatchIndex, httpMessage.IsLastBatch, this); // Clear the httpMessage set if (!clientWorkInMemory && httpMessage.Changes != null) { httpMessage.Changes.Clear(); } // Until we don't have received all the batches, wait for more if (!httpMessage.IsLastBatch) { return(new HttpMessageSendChangesResponse(httpMessage.SyncContext) { ServerStep = HttpStep.SendChangesInProgress }); } // ------------------------------------------------------------ // SECOND STEP : apply then return server changes // ------------------------------------------------------------ // get changes var(remoteClientTimestamp, serverBatchInfo, _, clientChangesApplied, serverChangesSelected) = await this.ApplyThenGetChangesAsync(httpMessage.Scope, sessionCache.ClientBatchInfo, cancellationToken, progress).ConfigureAwait(false); // Save the server batch info object to cache if not working in memory if (!clientWorkInMemory) { sessionCache.RemoteClientTimestamp = remoteClientTimestamp; sessionCache.ServerBatchInfo = serverBatchInfo; sessionCache.ServerChangesSelected = serverChangesSelected; sessionCache.ClientChangesApplied = clientChangesApplied; } // Get the firt response to send back to client return(await GetChangesResponseAsync(ctx, remoteClientTimestamp, serverBatchInfo, clientChangesApplied, serverChangesSelected, 0)); }