/// <summary> /// Internal load scope routine /// </summary> internal async Task <T> InternalGetScopeAsync <T>(SyncContext ctx, DbScopeType scopeType, string scopeName, DbScopeBuilder scopeBuilder, DbConnection connection, DbTransaction transaction, CancellationToken cancellationToken, IProgress <ProgressArgs> progress) where T : class { if (typeof(T) != typeof(ScopeInfo) && typeof(T) != typeof(ServerScopeInfo)) { throw new NotImplementedException($"Type {typeof(T).Name} is not implemented when trying to get a single instance"); } var scopes = await InternalGetAllScopesAsync <T>(ctx, scopeType, scopeName, scopeBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false); if (scopes == null || scopes.Count <= 0) { scopes = new List <T>(); // create a new scope id for the current owner (could be server or client as well) T scope = scopeType switch { DbScopeType.Client => new ScopeInfo { Id = Guid.NewGuid(), Name = scopeName, IsNewScope = true, LastSync = null, LastServerSyncTimestamp = null, LastSyncTimestamp = null, Version = SyncVersion.Current.ToString() } as T, DbScopeType.Server => new ServerScopeInfo { Name = scopeName, LastCleanupTimestamp = 0, Version = SyncVersion.Current.ToString() } as T, _ => throw new NotImplementedException($"Type {typeof(T).Name} is not implemented when trying to get a single instance") }; scope = await this.InternalSaveScopeAsync(ctx, scopeType, scope, scopeBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false); scopes.Add(scope); } // get first scope var localScope = scopes.FirstOrDefault(); if (typeof(T) == typeof(ScopeInfo)) { //check if we have already a good last sync. if no, treat it as new scopes.ForEach(sc => (sc as ScopeInfo).IsNewScope = (sc as ScopeInfo).LastSync == null); var scopeInfo = localScope as ScopeInfo; if (scopeInfo?.Schema != null) { scopeInfo.Schema.EnsureSchema(); } var scopeLoadedArgs = new ScopeLoadedArgs <ScopeInfo>(ctx, scopeName, scopeType, scopeInfo, connection, transaction); await this.InterceptAsync(scopeLoadedArgs, cancellationToken).ConfigureAwait(false); } else { var scopeInfo = localScope as ServerScopeInfo; if (scopeInfo?.Schema != null) { scopeInfo.Schema.EnsureSchema(); } var scopeLoadedArgs = new ScopeLoadedArgs <ServerScopeInfo>(ctx, scopeName, scopeType, scopeInfo, connection, transaction); await this.InterceptAsync(scopeLoadedArgs, cancellationToken).ConfigureAwait(false); } return(localScope); }
/// <summary> /// Get the local configuration, ensures the local scope is created /// </summary> /// <returns>current context, the local scope info created or get from the database and the configuration from the client if changed </returns> public async Task <ScopeInfo> GetClientScopeAsync(CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) { if (!this.StartTime.HasValue) { this.StartTime = DateTime.UtcNow; } // Get context or create a new one var ctx = this.GetContext(); ScopeInfo localScope = null; using (var connection = this.Provider.CreateConnection()) { try { ctx.SyncStage = SyncStage.ScopeLoading; // Open connection await this.OpenConnectionAsync(connection, cancellationToken).ConfigureAwait(false); using (var transaction = connection.BeginTransaction()) { await this.InterceptAsync(new TransactionOpenedArgs(ctx, connection, transaction), cancellationToken).ConfigureAwait(false); await this.InterceptAsync(new ScopeLoadingArgs(ctx, this.ScopeName, this.Options.ScopeInfoTableName, connection, transaction), cancellationToken).ConfigureAwait(false); ctx = await this.Provider.EnsureClientScopeAsync(ctx, this.Options.ScopeInfoTableName, connection, transaction, cancellationToken, progress).ConfigureAwait(false); (ctx, localScope) = await this.Provider.GetClientScopeAsync(ctx, this.Options.ScopeInfoTableName, this.ScopeName, connection, transaction, cancellationToken, progress).ConfigureAwait(false); await this.InterceptAsync(new TransactionCommitArgs(ctx, connection, transaction), cancellationToken).ConfigureAwait(false); transaction.Commit(); } ctx.SyncStage = SyncStage.ScopeLoaded; await this.CloseConnectionAsync(connection, cancellationToken).ConfigureAwait(false); var scopeArgs = new ScopeLoadedArgs(ctx, localScope, connection); await this.InterceptAsync(scopeArgs, cancellationToken).ConfigureAwait(false); this.ReportProgress(ctx, progress, scopeArgs); } catch (Exception ex) { RaiseError(ex); } finally { if (connection != null && connection.State == ConnectionState.Open) { connection.Close(); } } this.logger.LogInformation(SyncEventsId.GetClientScope, localScope); return(localScope); } }