Using Microsoft Sync Framework to sync files across network - wcf

The file synchronization example given here - http://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=sync&ReleaseId=3424 only talks about syncing files on the same machine. Has anyone come across a working example of using something like WCF to enable this to work for files across a network?
Bryant's example - http://bryantlikes.com/archive/2008/01/03/remote-file-sync-using-wcf-and-msf.aspx is not complete and is only a one way sync and is less than ideal.

The Sync framework can synchronize files across the network as long as you have an available network share.
In the constructor of the FileSyncProvider set the rootDirectoryPath to a network share location that you have read and write permissions to:
string networkPath = #"\\machinename\sharedfolderlocation";
FileSyncProvidor provider = new FileSyncProvider(networkPath);
To do a two way sync in this fashion you will need to create a FileSyncProvider for both the source and destination systems and use the SyncOrchestrator to do the heavy lifting for you.
An example:
string firstLocation = #"\\sourcemachine\sourceshare";
string secondLocation = #"\\sourcemachine2\sourceshare2";
FileSyncProvidor firstProvider = new FileSyncProvider(firstLocation);
FileSyncProvidor secondProvider = new FileSyncProvider(secondLocation);
SyncOrchestrator orchestrator = new SyncOrchestrator();
orchestrator.LocalProvider = firstProvider;
orchestrator.RemoteProvider = secondProvider;
orchestrator.Direction = SyncDirectionOrder.DownloadAndUpload;
What this does is define two filesync providers and the orchestrator will sync the files in both directions. It tracks creates, modifications, and deletes of files in the directories set in the providers.
All that is needed at this point is to call Synchronize on the SyncOrchestrator:
orchestrator.Synchronize();

Related

How do I launch a SmartSim orchestrator without models?

I'm trying to prototype using the SmartRedis Python client to interact with the SmartSim Orchestrator. Is it possible to launch the orchestrator without any other models in the experiment? If so, what would be the best way to do so?
It is entirely possible to do that. A SmartSim Experiment can contain different types of 'entities' including Models, Ensembles (i.e. groups of Models), and Orchestrator (i.e. the Redis-backed database). None of these entities, however, are 'required' to be in the Experiment.
Here's a short script that creates an experiment which includes only a database.
from SmartSim import Experiment
NUM_DB_NODES = 3
exp = Experiment("Database Only")
db = exp.create_database(db_nodes=NUM_DB_NODES)
exp.generate(db)
exp.start(db)
After this, the Orchestrator (with the number of shards specified by NUM_DB_NODES) will have been spunup. You can then connect the Python client using the following line:
client = smartredis.Client(db.get_address()[0],NUM_DB_NODES>1)

ArcGis Offline map layer changes synchronization

In my WPF application I’m trying to use off-line map functionality. Right now my feature service is configured for data sync and I’m able to create data replica on server and download local copy of geodatabase.
gdbSyncTask = await GeodatabaseSyncTask.CreateAsync(_featureServiceUri);
Envelope extent = new Envelope(xmin, ymin, xmax, ymax, new SpatialReference(wkidStart));
GenerateGeodatabaseParameters generateParams = await _gdbSyncTask.CreateDefaultGenerateGeodatabaseParametersAsync(extent);
_generateGdbJob = _gdbSyncTask.GenerateGeodatabase(generateParams, _gdbPath);
_generateGdbJob.JobChanged += GenerateGdbJobChanged;
_generateGdbJob.ProgressChanged += ((object sender, EventArgs e) =>
{
UpdateProgressBar();
});
_generateGdbJob.Start();
After initial synchronization, I’m able to successfully work with map in off-line mode. This includes operations like adding new geometries or editing existing polygons inside local DB.
However, when I’m trying to synchronize changes back to server – I’m getting no results.
To perform data synchronization with local database – I’m using the following code:
SyncGeodatabaseParameters parameters = new SyncGeodatabaseParameters()
{
GeodatabaseSyncDirection = SyncDirection.Bidirectional,
RollbackOnFailure = false
};
Geodatabase gdb = await Geodatabase.OpenAsync(this.GetGdbPath());
foreach (GeodatabaseFeatureTable table in gdb.GeodatabaseFeatureTables)
{
long id = table.ServiceLayerId;
SyncLayerOption option = new SyncLayerOption(id);
option.SyncDirection = SyncDirection.Bidirectional;
parameters.LayerOptions.Add(option);
}
_gdbSyncTask = await GeodatabaseSyncTask.CreateAsync(_featureServiceUri);
SyncGeodatabaseJob job = _gdbSyncTask.SyncGeodatabase(parameters, gdb);
job.JobChanged += SyncJob_JobChanged;
job.ProgressChanged += SyncJob_ProgressChanged;
job.Start();
Everything goes well. The synchronization ends with status “Succeeded”. The messages logged by the SyncGeodatabaseJob are like on the screen below:
However – when I open edited feature layer from server inside map web client I cannot found any of my local changes. In the serve database I can also see that no new records were created during synchronization.
Interesting think is that when I open “Replica” data inside web I can see the following information:
Replica Server Gen: 2
Creation Date: 2018/02/07 10:49:54 UTC
Last Sync Date: 2018/02/07 10:49:54 UTC
The “Last Sync Data” is equal to replica “Creation date” However, in the replica log in ArcMap I can see the following information:
Can anyone can tell me how should I interpret above described situation? Am I missing some steps in my code? Or maybe some configuration feature is missing on the server? It looks like data modifications are successfully pushed back to replica on server but after that replica is not synchronized with server database (should it work automatically?).
I’m a “fresh” person regarding ArcGis development so any help will be appreciated
Thanks for all the answers. It occurred that there is versioning enabled on the server database and the offline, versioned changes was not reconciled to the server.
After running reconcile/post script (http://desktop.arcgis.com/en/arcmap/10.3/manage-data/geodatabases/automate-reconcile-post-after-sync.htm) off-line changes started to be visibile to other system users.
The code looks ok on fast look so I would assume that there is something going on in the setup.
What do you get back from the sync operation after the sync has completed? Note that you can just use await syncJob.GetResultsAsync to start the job and wait the results.
How is the Feature Service set up on the server? Please refer https://enterprise.arcgis.com/en/server/latest/publish-services/linux/prepare-data-for-offline-use.htm for the different ways to set these things.

Automatically Sync SQL Databases across two computers

I am using a cloud backup/sync service (SpiderOak) which automatically Syncs folders across several computers / devices.
I am trying to figure out a way to automatically sync all my databases across my work computer and personal laptop, without actually needing to backup/restore from one instance to the other.
So what I am thinking of is to create a new sql instance on my laptop which is identical to my work desktop instance, then to pick both SQL Server directories in Program Files to sync with each other using SpiderOak (the whole root SQL Server folders).
Will this be enough for my two instances to Sync with each other? Meaning if I create a new database on my computer at work, will I see this database on my laptop when I open SQL Server Database Management Studio?
I am almost sure if databases already exist they will sync with each other (since the root folders contain the mdf & ldf files - but correct me if I am wrong). however, I am not sure if a new database will be created if it doesn't already exist on one of the machines.
Is there any other folders that I need to sync other than the ones I specified already?
You could use Sql Sync Framework, you can download it here
some more readfood
It works for Sql Server 2005
Download and import references and include with the default ones:
using System.Data.Sql;
using System.Data.SqlClient;
using Microsoft.Synchronization;
using Microsoft.Synchronization.Data;
using Microsoft.Synchronization.Data.SqlServer;
using System.Diagnostics;
using System.Reflection;
using System.Net;
Than the actual code:
private void SyncTables()
{
SqlConnection ConStringOnline = new SqlConnection("connstring");
SqlConnection ConStringOffline = new SqlConnection("connString");
SyncOrchestrator sync = new SyncOrchestrator();
sync.Direction = SyncDirectionOrder.Download; //or DownloadAndUpload
//the 'scope1' is important, read more about it in the articles
var provider1 = new SqlSyncProvider("scope1", ConStringOnline);
var provider2 = new SqlSyncProvider("scope1", ConStringOffline);
PrepareServerForProvisioning(provider1);
PrepareClientForProvisioning(provider2, ConStringOnline);
sync.LocalProvider = provider2;
sync.RemoteProvider = provider1;
sync.Synchronize();
}
private static void PrepareServerForProvisioning(SqlSyncProvider provider)
{
SqlConnection connection = (SqlConnection)provider.Connection;
SqlSyncScopeProvisioning config = new SqlSyncScopeProvisioning(connection);
if (!config.ScopeExists(provider.ScopeName))
{
DbSyncScopeDescription scopeDesc = new DbSyncScopeDescription(provider.ScopeName);
scopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable("TABLENAME", connection));
config.PopulateFromScopeDescription(scopeDesc);
config.SetCreateTableDefault(DbSyncCreationOption.CreateOrUseExisting);
config.Apply();
}
}
private static void PrepareClientForProvisioning(SqlSyncProvider provider, SqlConnection sourceConnection)
{
SqlSyncScopeProvisioning config = new SqlSyncScopeProvisioning((SqlConnection)provider.Connection);
if (!config.ScopeExists(provider.ScopeName))
{
DbSyncScopeDescription scopeDesc = SqlSyncDescriptionBuilder.GetDescriptionForScope(provider.ScopeName, sourceConnection);
config.PopulateFromScopeDescription(scopeDesc);
config.Apply();
}
}
The downside of using Sync Framework: It is a pain in the a** to add these prerequisites to your application before publishing, no problem if you just use an application for yourself or for your company, but when you would like to publish it online it is a bit harder. I already had a topic about that
However, when using tools like InnoScript, you can install the prerequisites easily while installing the application. Here is how.
Now for the ScopeName: It is important that you don't use twice the same name, I believe. I had multiple tables so I just named them scope1,scope2,scope3,scope4. Apparently Sync Framework does the rest of the work for you. It also automatically adds _tracking tables to your database, this is just metadata to store information to synchronize properly.

Is it necessary that Data Source of connection string must match the system name

This is my first post to this precious website. I am a new learner of vb.net. I am working on a simple purchase project, where i got some errors. But the first thing is which baffled me is:
This is my connection string at module level, on the developed machine.
Public strCn As String = "Data Source = (local); Initial Catalog = PSys; Integrated Security = false; User ID = sa; Password = 123;"
Is it mandatory that Data Source must be the original name of the System Name. I mean If i use (local) or using ( . ), so will it work or not? Because when i copy my project to any other system for further development so every time i need to change the Data source, otherwise i get the error that: "Network-related or instance-specific error occurred......."
Kindly guide me that what i need to do.
When you are developing an application which uses a database server such as MsSQL it is not wise to install the server along with your application in every pc which is installed to. For example what are you going to do if a customer has a local network with 10 computers? Are you going to install SQL server in all 10 of them? And if so what if they need to share data?
So your best approach (based on common practice by other applications) will be to allow the user to install the SQL server where he wants and let him configure your application and point it to the server's location. If you follow that path then the configuration of your application can be in the setup application or in the application itself.
Now about the development phase, I had a similar situation in which I needed to develop the same application in two different computers. What I did was to install the SQL server in both of them with a named instance "sqlexpress" then in the application I used the
Data.SqlClient.SqlConnectionStringBuilder
class to build the connection string. I did something like this:
Public Function getDevConnectionString() As String
Dim csb As New Data.SqlClient.SqlConnectionStringBuilder(My.Settings.dbConnectionString) '<-My original cs in app settings
csb.DataSource = My.Computer.Name & "\sqlexpress"
Return csb.ConnectionString
End Function
Whenever I need a connection string I simply call getDevConnectionString() which returns the connection string based on the computer name plus the sql server instance name. For example:
Dim cs As String
#If DEBUG Then
cs = getDevConnectionString()
#Else
cs = getReleaseConnectionString()
#End If
where getReleaseConnectionString() is the function that returns your connection string configured by the customer.
Hope this point you the right direction...

WebSharingAppDemo-CEProviderEndToEnd Queries peerProvider for NeedsScope before any files are batched to the server. This seems out of order?

I'm building an application based on the WebSharingAppDemo-CEProviderEndToEnd. When I deploy the server portion on a server, the code gives the error "The path is not valid. Check the directory for the database." during the call to NeedsScope() in the CeWebSyncService.cs file.
Obviously the server can't access the client's sdf but what is supposed to happen to make this work? The app uses batching to send the data and the batches have to be marshalled across to the temp directory but this problem is occurring before any files have been batched over. There is nothing for the server to look at to determine whether the peerProivider needs scope. What am I missing?
public bool NeedsScope()
{
Log("NeedsSchema: {0}", this.peerProvider.Connection.ConnectionString);
SqlCeSyncScopeProvisioning prov = new SqlCeSyncScopeProvisioning();
return !prov.ScopeExists(this.peerProvider.ScopeName, (SqlCeConnection)this.peerProvider.Connection);
}
I noticed that the sample was making use of a proxy to speak w/ the CE file but a provider (not a proxy) to speak w/ the sql server.
I switched it so there is a proxy to reach the SQL server and a provider to access the CE file.
That seems to work for me.
stats = synchronizationHelper.SynchronizeProviders(srcProvider, destinationProxy);
vs.
SyncOperationStatistics stats = syncHelper.SynchronizeProviders(srcProxy, destinationProvider);