private async void Handle_Clicked(object sender, System.EventArgs e) { try { // Use this when you want to use sqlite on ios SQLitePCL.Batteries_V2.Init(); // 10.0.2.2 is a special url to be able to reach the machine localhost web api var serverOrchestrator = new WebClientOrchestrator("http://10.0.2.2:50886/api/sync"); // Path the local sqlite database string dbPath = Path.Combine(Xamarin.Essentials.FileSystem.AppDataDirectory, "SqliteDatabase.db3"); var clientOptions = new SyncOptions { BatchSize = 3000 }; // Sqlite Client provider var clientProvider = new SqliteSyncProvider(dbPath); // Creating an agent that will handle all the process var agent = new SyncAgent(clientProvider, serverOrchestrator, clientOptions); var progress = new Progress <ProgressArgs>(args => lblProgress.Text = $"{args.Context.SyncStage}:{args.Message}"); // Launch the sync process var s1 = await agent.SynchronizeAsync(progress); // See results lblResult.Text = s1.ToString(); } catch (Exception ex) { lblResult.Text = ex.Message; } }
public static async Task SynchronizeDefaultAsync(WebClientOrchestrator serverOrchestrator, SqlSyncProvider clientProvider, SyncOptions options, bool reinitialize = false) { var agent = new SyncAgent(clientProvider, serverOrchestrator, options); agent.Parameters.Add("City", "Toronto"); agent.Parameters.Add("postal", DBNull.Value); var syncType = reinitialize ? SyncType.Reinitialize : SyncType.Normal; var progress = new SynchronousProgress <ProgressArgs>( pa => Console.WriteLine($"{pa.ProgressPercentage:p}\t {pa.Message}")); try { // Launch the sync process var s1 = await agent.SynchronizeAsync(syncType, progress); // Write results Console.WriteLine(s1); } catch (Exception ex) { Console.WriteLine(ex.Message); } }
/// <summary> /// Intercept the provider when an http call to get scope is done /// </summary> public static void OnHttpGettingScopeResponse(this WebClientOrchestrator orchestrator, Func <HttpGettingScopeResponseArgs, Task> action) => orchestrator.SetInterceptor(action);
/// <summary> /// Intercept the provider when an http is about to be done to get server scope /// </summary> public static void OnHttpGettingScopeRequest(this WebClientOrchestrator orchestrator, Action <HttpGettingScopeRequestArgs> action) => orchestrator.SetInterceptor(action);
private static async Task SynchronizeAsync(CoreProvider clientProvider) { // Database script used for this sample : https://github.com/Mimetis/Dotmim.Sync/blob/master/CreateAdventureWorks.sql var serverOrchestrator = new WebClientOrchestrator("https://localhost:44342/api/sync"); // Creating an agent that will handle all the process var agent = new SyncAgent(clientProvider, serverOrchestrator); try { var progress = new SynchronousProgress <ProgressArgs>(args => Console.WriteLine($"{args.PogressPercentageString}:\t{args.Message}")); // Get the client scope var scope = await agent.LocalOrchestrator.GetClientScopeAsync(); if (scope.IsNewScope) { var client = new HttpClient(); var seedingsResponse = await client.GetAsync($"https://localhost:44342/api/sync/seedings/{scope.Id}"); seedingsResponse.EnsureSuccessStatusCode(); var seedingsResponseString = await seedingsResponse.Content.ReadAsStringAsync(); var seedings = JsonConvert.DeserializeObject <List <Seeding> >(seedingsResponseString); agent.LocalOrchestrator.OnTableCreating(async tca => { var tableName = tca.TableName.Unquoted().ToString(); var schemaName = string.IsNullOrEmpty(tca.TableName.SchemaName) ? "dbo" : tca.TableName.SchemaName; var seeding = seedings.FirstOrDefault(s => s.TableName == tableName && s.SchemaName == schemaName); var id = tca.Table.GetPrimaryKeysColumns().ToList()[0]; if (seeding != null && id.IsAutoIncrement) { id.AutoIncrementSeed = seeding.Seed; id.AutoIncrementStep = seeding.Step; } var newTableBuilder = agent.LocalOrchestrator.GetTableBuilder(tca.Table, agent.LocalOrchestrator.Setup); var newCommand = await newTableBuilder.GetCreateTableCommandAsync(tca.Connection, tca.Transaction); tca.Command.CommandText = newCommand.CommandText; }); } // Launch the sync process var s1 = await agent.SynchronizeAsync(progress); // Write results Console.WriteLine(s1); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.WriteLine("End"); }
/// <summary> /// Intercept the provider when client is trying to send again an http request message /// </summary> public static void OnHttpPolicyRetrying(this WebClientOrchestrator orchestrator, Func <HttpSyncPolicyArgs, Task> action) => orchestrator.SetInterceptor(action);
/// <summary> /// Intercept the provider when batches are about to be downloaded /// </summary> public static void OnHttpBatchesDownloadingArgs(this WebClientOrchestrator orchestrator, Action <HttpBatchesDownloadingArgs> action) => orchestrator.SetInterceptor(action);
/// <summary> /// Intercept the provider when batches have been completely downloaded /// </summary> public static void OnHttpBatchesDownloadedArgs(this WebClientOrchestrator orchestrator, Func <HttpBatchesDownloadedArgs, Task> action) => orchestrator.SetInterceptor(action);
/// <summary> /// Intercept the provider when a batch changes has been downloaded from server side /// </summary> public static void OnHttpGettingChangesResponse(this WebClientOrchestrator orchestrator, Action <HttpGettingServerChangesResponseArgs> action) => orchestrator.SetInterceptor(action);
/// <summary> /// Intercept the provider when downloading a batch changes from server side. /// </summary> public static void OnHttpGettingChangesRequest(this WebClientOrchestrator orchestrator, Func <HttpGettingServerChangesRequestArgs, Task> action) => orchestrator.SetInterceptor(action);
/// <summary> /// Intercept the provider when batch changes is uploading to server. /// </summary> public static void OnHttpSendingChangesRequest(this WebClientOrchestrator orchestrator, Action <HttpSendingClientChangesRequestArgs> action) => orchestrator.SetInterceptor(action);
internal SyncContext Sync(string value) { if (String.IsNullOrEmpty(value)) { throw new Exception("Loading a project requires a name. Ex : dotnet sync --load project01"); } Project project = DataStore.Current.LoadProject(value); if (project == null) { throw new Exception($"Project {value} does not exists."); } if (project.ServerProvider == null || string.IsNullOrEmpty(project.ServerProvider.ConnectionString)) { throw new Exception($"Server provider for project {project.Name} is not correctly defined. See help: dotnet sync provider --help"); } if (project.ClientProvider == null || string.IsNullOrEmpty(project.ClientProvider.ConnectionString)) { throw new Exception($"Client provider for project {project.Name} is not correctly defined. See help: dotnet sync provider --help"); } if (project.ServerProvider.ProviderType != ProviderType.Web && (project.Tables == null || project.Tables.Count <= 0)) { throw new Exception($"No table configured for project {project.Name}. See help: dotnet sync table --help"); } IRemoteOrchestrator remoteOrchestrator; ILocalOrchestrator localOrchestrator; switch (project.ServerProvider.ProviderType) { case ProviderType.Sqlite: throw new Exception("Can't use Sqlite as a server provider"); case ProviderType.Web: remoteOrchestrator = new WebClientOrchestrator(new Uri(project.ServerProvider.ConnectionString)); break; case ProviderType.MySql: remoteOrchestrator = new RemoteOrchestrator(new MySqlSyncProvider(project.ServerProvider.ConnectionString)); break; case ProviderType.SqlServer: default: remoteOrchestrator = new RemoteOrchestrator(new SqlSyncProvider(project.ServerProvider.ConnectionString)); break; } switch (project.ClientProvider.ProviderType) { case ProviderType.Web: throw new Exception("Web proxy is used as a proxy server. You have to use an ASP.NET web backend. CLI uses a proxy as server provider"); case ProviderType.Sqlite: localOrchestrator = new LocalOrchestrator(new SqliteSyncProvider(project.ClientProvider.ConnectionString)); break; case ProviderType.MySql: localOrchestrator = new LocalOrchestrator(new MySqlSyncProvider(project.ClientProvider.ConnectionString)); break; case ProviderType.SqlServer: default: localOrchestrator = new LocalOrchestrator(new SqlSyncProvider(project.ClientProvider.ConnectionString)); break; } SyncAgent agent = null; if (project.ServerProvider.ProviderType != ProviderType.Web) { agent = new SyncAgent(localOrchestrator, remoteOrchestrator); var syncSchema = new SyncSchema(); //var syncConfiguration = agent.LocalOrchestrator.Configuration; foreach (var t in project.Tables.OrderBy(tbl => tbl.Order)) { // Potentially user can pass something like [SalesLT].[Product] // or SalesLT.Product or Product. ParserName will handle it var parser = ParserName.Parse(t.Name); var tableName = parser.ObjectName; var schema = string.IsNullOrEmpty(t.Schema) ? parser.SchemaName : t.Schema; var dmTable = new DmTable(tableName); if (!String.IsNullOrEmpty(schema)) { dmTable.Schema = schema; } dmTable.SyncDirection = t.Direction; agent.SetSchema(agentSchema => agentSchema.Add(dmTable)); } agent.SetOptions(o => o.BatchDirectory = string.IsNullOrEmpty(project.Configuration.BatchDirectory) ? null : project.Configuration.BatchDirectory); agent.SetOptions(o => o.BatchSize = (int)Math.Min(Int32.MaxValue, project.Configuration.DownloadBatchSizeInKB)); //agent.SetOptions(o => o.SerializationFormat = project.Configuration.SerializationFormat); //agent.Options.UseBulkOperations = project.Configuration.UseBulkOperation; agent.SetSchema(agentSchema => { agentSchema.ConflictResolutionPolicy = project.Configuration.ConflictResolutionPolicy; }); } else { agent = new SyncAgent(localOrchestrator, remoteOrchestrator); } agent.LocalOrchestrator.OnTableChangesSelected(tcs => Console.WriteLine($"Changes selected for table {tcs.TableChangesSelected.TableName}: {tcs.TableChangesSelected.TotalChanges}")); agent.LocalOrchestrator.OnTableChangesApplied(tca => Console.WriteLine($"Changes applied for table {tca.TableChangesApplied.Table.TableName}: [{tca.TableChangesApplied.State}] {tca.TableChangesApplied.Applied}")); // synchronous call var syncContext = agent.SynchronizeAsync().GetAwaiter().GetResult(); var tsEnded = TimeSpan.FromTicks(syncContext.CompleteTime.Ticks); var tsStarted = TimeSpan.FromTicks(syncContext.StartTime.Ticks); var durationTs = tsEnded.Subtract(tsStarted); var durationstr = $"{durationTs.Hours}:{durationTs.Minutes}:{durationTs.Seconds}.{durationTs.Milliseconds}"; Console.ForegroundColor = ConsoleColor.Green; var s = $"Synchronization done. " + Environment.NewLine + $"\tTotal changes downloaded: {syncContext.TotalChangesDownloaded} " + Environment.NewLine + $"\tTotal changes uploaded: {syncContext.TotalChangesUploaded}" + Environment.NewLine + $"\tTotal duration :{durationstr} "; Console.WriteLine(s); Console.ResetColor(); return(syncContext); }
/// <summary> /// Test a client syncing through a web api /// </summary> private static async Task SyncThroughWebApiAsync() { var clientProvider = new SqlSyncProvider(DbHelper.GetDatabaseConnectionString(clientDbName)); var handler = new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip }; var client = new HttpClient(handler) { Timeout = TimeSpan.FromMinutes(5) }; var proxyClientProvider = new WebClientOrchestrator("http://localhost:52288/api/Sync", null, null, client); // ---------------------------------- // Client side // ---------------------------------- var clientOptions = new SyncOptions { ScopeInfoTableName = "client_scopeinfo", BatchDirectory = Path.Combine(SyncOptions.GetDefaultUserBatchDiretory(), "sync_client"), BatchSize = 50, CleanMetadatas = true, UseBulkOperations = true, UseVerboseErrors = false, }; var clientSetup = new SyncSetup { StoredProceduresPrefix = "cli", StoredProceduresSuffix = "", TrackingTablesPrefix = "cli", TrackingTablesSuffix = "", TriggersPrefix = "", TriggersSuffix = "", }; var agent = new SyncAgent(clientProvider, proxyClientProvider, clientSetup, clientOptions); Console.WriteLine("Press a key to start (be sure web api is running ...)"); Console.ReadKey(); do { Console.Clear(); Console.WriteLine("Web sync start"); try { var progress = new SynchronousProgress <ProgressArgs>(pa => Console.WriteLine($"{pa.Context.SessionId} - {pa.Context.SyncStage}\t {pa.Message}")); var s = await agent.SynchronizeAsync(progress); Console.WriteLine(s); } catch (SyncException e) { Console.WriteLine(e.Message); } catch (Exception e) { Console.WriteLine("UNKNOW EXCEPTION : " + e.Message); } Console.WriteLine("Sync Ended. Press a key to start again, or Escapte to end"); } while (Console.ReadKey().Key != ConsoleKey.Escape); Console.WriteLine("End"); }
public static async Task SyncHttpThroughKestellAsync() { // server provider // Create 2 Sql Sync providers var serverProvider = new SqlSyncProvider(DbHelper.GetDatabaseConnectionString(serverDbName)); var clientProvider = new SqlSyncProvider(DbHelper.GetDatabaseConnectionString(clientDbName)); // ---------------------------------- // Client side // ---------------------------------- var clientOptions = new SyncOptions { BatchSize = 500 }; var proxyClientProvider = new WebClientOrchestrator(); // ---------------------------------- // Web Server side // ---------------------------------- var setup = new SyncSetup(allTables) { ScopeName = "all_tables_scope", StoredProceduresPrefix = "s", StoredProceduresSuffix = "", TrackingTablesPrefix = "t", TrackingTablesSuffix = "", TriggersPrefix = "", TriggersSuffix = "t" }; // snapshot directory var directory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Snapshots"); // ---------------------------------- // Create a snapshot // ---------------------------------- Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine($"Creating snapshot"); var remoteOrchestrator = new RemoteOrchestrator(serverProvider); await remoteOrchestrator.CreateSnapshotAsync(new SyncContext(), setup, directory, 500, CancellationToken.None); Console.WriteLine($"Done."); Console.ResetColor(); // ---------------------------------- // Insert a value after snapshot created // ---------------------------------- using (var c = serverProvider.CreateConnection()) { var command = c.CreateCommand(); command.CommandText = "INSERT INTO [dbo].[ProductCategory] ([Name]) VALUES ('Bikes revolution');"; c.Open(); command.ExecuteNonQuery(); c.Close(); } var webServerOptions = new WebServerOptions { SnapshotsDirectory = directory }; // Creating an agent that will handle all the process var agent = new SyncAgent(clientProvider, proxyClientProvider); agent.Options = clientOptions; var configureServices = new Action <IServiceCollection>(services => { services.AddSyncServer <SqlSyncProvider>(serverProvider.ConnectionString, setup, webServerOptions); }); var serverHandler = new RequestDelegate(async context => { var webProxyServer = context.RequestServices.GetService(typeof(WebProxyServerOrchestrator)) as WebProxyServerOrchestrator; await webProxyServer.HandleRequestAsync(context); }); using (var server = new KestrellTestServer(configureServices)) { var clientHandler = new ResponseDelegate(async(serviceUri) => { proxyClientProvider.ServiceUri = serviceUri; do { Console.Clear(); Console.WriteLine("Web sync start"); try { var progress = new SynchronousProgress <ProgressArgs>(pa => Console.WriteLine($"{pa.Context.SyncStage}\t {pa.Message}")); var s = await agent.SynchronizeAsync(progress); Console.WriteLine(s); } catch (SyncException e) { Console.WriteLine(e.ToString()); } catch (Exception e) { Console.WriteLine("UNKNOW EXCEPTION : " + e.Message); } Console.WriteLine("Sync Ended. Press a key to start again, or Escapte to end"); } while (Console.ReadKey().Key != ConsoleKey.Escape); }); await server.Run(serverHandler, clientHandler); } }
/// <summary> /// Intercept the provider when an http message response is downloaded from remote side /// </summary> public static void OnHttpGettingResponse(this WebClientOrchestrator orchestrator, Action <HttpGettingResponseMessageArgs> action) => orchestrator.SetInterceptor(action);
/// <summary> /// Intercept the provider when an http request message is sent /// </summary> public static void OnHttpSendingRequest(this WebClientOrchestrator orchestrator, Func <HttpSendingRequestMessageArgs, Task> action) => orchestrator.SetInterceptor(action);