Como sincronizar arquivos usando código gerenciado

Este tópico mostra como usar uma linguagem gerenciada, como C# ou Visual Basic para criar um aplicativo que sincronize os arquivos e as subpastas usando o provedor de sincronização de arquivos do Sync Framework.

Os exemplos neste tópico se concentram nos seguintes tipos do Sync Framework:

Noções básicas sobre sincronização de arquivos

O Sync Framework implementa um provedor de sincronização que pode ser usado para sincronizar arquivos e subpastas contidos em uma pasta em um sistema de arquivos. Esse provedor expõe várias configurações modificáveis para exercer mais controle sobre exatamente como a sincronização ocorre e quais itens são sincronizados. Para sincronizar arquivos entre duas pastas, um aplicativo executa estas etapas básicas:

  1. Cria um FileSyncProvider objeto para representar cada pasta.

  2. Passa os dois provedores para um objeto SyncOrchestrator e especifica um como o provedor de origem e o outro como o provedor de destino.

  3. Chama Synchronize para iniciar a sessão de sincronização.

Para obter mais informações sobre a sincronização de arquivos, consulte Sincronizando arquivos.

Exemplo

O código de exemplo nesta seção é de um aplicativo de console que sincroniza dois diretórios, inclusive os subdiretórios e os arquivos desses diretórios. O código de exemplo mostra as seguintes tarefas:

  • Como definir opções de sincronização.

  • Como executar a detecção de alterações explicitamente para uma réplica.

  • Como especificar um filtro que controle quais itens são incluídos na sincronização.

  • Como manipular os conflitos que podem ocorrer durante a sincronização.

  • Como sincronizar duas réplicas.

Após a exposição desses exemplos de código, foi incluído o código completo para o aplicativo, de forma que você possa criá-lo e executá-lo.

Definindo opções de sincronização

O objeto FileSyncOptions permite definir várias opções para a sincronização de arquivos, inclusive como detectar alterações e definir se, durante a sincronização, os itens devem ser excluídos ou movidos para a Lixeira. O exemplo de código a seguir define quatro opções, três das quais são relacionadas a exclusões de itens. A opção ExplicitDetectChanges significa que o Sync Framework não executará a detecção de alterações, a não ser que o aplicativo chame DetectChanges explicitamente. Isso será explicado na próxima seção, "Executando a detecção de alterações".

FileSyncOptions options = FileSyncOptions.ExplicitDetectChanges |
         FileSyncOptions.RecycleDeletedFiles | FileSyncOptions.RecyclePreviousFileOnUpdates | 
         FileSyncOptions.RecycleConflictLoserFiles;
Dim options As FileSyncOptions = _
    FileSyncOptions.ExplicitDetectChanges Or FileSyncOptions.RecycleDeletedFiles _
    Or FileSyncOptions.RecyclePreviousFileOnUpdates _
    Or FileSyncOptions.RecycleConflictLoserFiles

Executando a detecção de alterações

Por padrão, o Sync Framework executa a detecção de alterações em ambas as réplicas sempre que Synchronize é chamado. A detecção de alterações permite que o Sync Framework determine quais itens devem ser enviados da origem para o destino e quais itens, se houver, estão em conflito. Especificando ExplicitDetectChanges, é possível controlar quando a detecção de alterações é executada. O exemplo de código a seguir chama a detecção de alterações para cada réplica antes que Synchronize seja chamado. O objetivo deste exemplo é ilustrar DetectChanges, mas tem o benefício de apresentar uma passagem de detecção de alterações em vez das duas que ocorreriam ao executar a sincronização bidirecional posteriormente no aplicativo.

DetectChangesOnFileSystemReplica(
    replica1RootPath, filter, options);
DetectChangesOnFileSystemReplica(
    replica2RootPath, filter, options);
public static void DetectChangesOnFileSystemReplica(
        string replicaRootPath,
        FileSyncScopeFilter filter, FileSyncOptions options)
{
    FileSyncProvider provider = null;

    try
    {
        provider = new FileSyncProvider(replicaRootPath, filter, options);
        provider.DetectChanges();
    }
    finally
    {
        // Release resources.
        if (provider != null)
            provider.Dispose();
    }
}
DetectChangesOnFileSystemReplica(replica1RootPath, filter, options)
DetectChangesOnFileSystemReplica(replica2RootPath, filter, options)
Public Shared Sub DetectChangesOnFileSystemReplica(ByVal replicaRootPath As String, ByVal filter As FileSyncScopeFilter, _
                                                   ByVal options As FileSyncOptions)
    Dim provider As FileSyncProvider = Nothing

    Try
        provider = New FileSyncProvider(replicaRootPath, filter, options)
        provider.DetectChanges()
    Finally
        ' Release resources. 
        If provider IsNot Nothing Then
            provider.Dispose()
        End If
    End Try
End Sub

Especificando um filtro estático

Os filtros estáticos podem ser definidos para excluir arquivos por nome (inclusive nomes curinga) e por atributo. Esses filtros também podem ser definidos para excluir o conteúdo de subpastas inteiras. Também é possível especificar uma lista explícita de nomes de arquivos para incluir (inclusive nomes curinga). Para ser incluído no escopo, um arquivo ou uma pasta deve passar por todos os filtros. Por exemplo, se todos os arquivos com uma extensão .txt forem excluídos do escopo e o arquivo MyFile.txt for especificado na lista de arquivos a serem incluídos explicitamente no escopo, MyFile.txt será excluído por causa da sua extensão .txt.

O exemplo de código a seguir usa o objeto FileSyncScopeFilter para criar um filtro que exclui todos os arquivos *.lnk. Um filtro não tem relação com o provedor que o criou. Para conectar um filtro a um provedor, passe o filtro para um dos construtores de FileSyncProvider ou defina a propriedade ScopeFilter. No aplicativo de exemplo, isso é feito no método DetectChangesOnFileSystemReplica(), porque o filtro só é pertinente para detecção de alterações. Como o filtro é independente do provedor, apenas um filtro deve ser criado por sessão de sincronização; os provedores não devem usar filtros diferentes, pois isso pode levar à não convergência de dados.

FileSyncScopeFilter filter = new FileSyncScopeFilter();
filter.FileNameExcludes.Add("*.lnk");
Dim filter As New FileSyncScopeFilter()
filter.FileNameExcludes.Add("*.lnk")

Além dos filtros estáticos, também é possível excluir arquivos durante a sincronização por meio da manipulação de um evento gerado pelo provedor. Para obter mais informações, consulte Controlando quais arquivos são sincronizados.

Manipulando conflitos

O Sync Framework detecta e resolve conflitos de simultaneidade e conflitos de restrição de arquivos e pastas. Um conflito de simultaneidade ocorre quando o mesmo item é alterado em ambas as réplicas desde a última sessão de sincronização entre essas réplicas. Um conflito de restrição ocorrerá se um arquivo ou uma pasta com o mesmo nome for adicionado a ambas as réplicas. Os conflitos são resolvidos com a manutenção do arquivo ou da pasta que tem a alteração mais recente e a exclusão (ou movimentação) do arquivo ou da pasta que tem a alteração mais antiga. Para arquivos, também existe a opção de especificar que a origem ou o destino devem vencer o conflito, independentemente de qual alteração ocorreu primeiro. O exemplo de código a seguir registra os manipuladores dos eventos ItemConflicting e ItemConstraint que estão disponíveis por meio do objeto SyncCallbacks. Os métodos chamados resolvem todos os conflitos a favor da origem e gravam as informações no console.

Dim destinationCallbacks As SyncCallbacks = destinationProvider.DestinationCallbacks
AddHandler destinationCallbacks.ItemConflicting, AddressOf OnItemConflicting
AddHandler destinationCallbacks.ItemConstraint, AddressOf OnItemConstraint
SyncCallbacks destinationCallbacks = destinationProvider.DestinationCallbacks;
destinationCallbacks.ItemConflicting += new EventHandler<ItemConflictingEventArgs>(OnItemConflicting);
destinationCallbacks.ItemConstraint += new EventHandler<ItemConstraintEventArgs>(OnItemConstraint);
public static void OnItemConflicting(object sender, ItemConflictingEventArgs args)
{
    args.SetResolutionAction(ConflictResolutionAction.SourceWins);
    Console.WriteLine("-- Concurrency conflict detected for item " + args.DestinationChange.ItemId.ToString());
}

public static void OnItemConstraint(object sender, ItemConstraintEventArgs args)
{
    args.SetResolutionAction(ConstraintConflictResolutionAction.SourceWins);
    Console.WriteLine("-- Constraint conflict detected for item " + args.DestinationChange.ItemId.ToString());
}
Public Shared Sub OnItemConflicting(ByVal sender As Object, ByVal args As ItemConflictingEventArgs)
    args.SetResolutionAction(ConflictResolutionAction.SourceWins)
    Console.WriteLine("-- Concurrency conflict detected for item " & args.DestinationChange.ItemId.ToString())
End Sub

Public Shared Sub OnItemConstraint(ByVal sender As Object, ByVal args As ItemConstraintEventArgs)
    args.SetResolutionAction(ConstraintConflictResolutionAction.SourceWins)
    Console.WriteLine("-- Constraint conflict detected for item " & args.DestinationChange.ItemId.ToString())
End Sub

Sincronizando duas réplicas

Depois que as opções e os filtros são definidos, o aplicativo sincroniza as duas réplicas criando uma instância de um SyncOrchestrator e chamando o método Synchronize. O exemplo de código a seguir especifica o provedor de cada réplica, define as opções, registra os manipuladores de eventos, especifica uma direção de sincronização de Upload e chama Synchronize. O método é chamado duas vezes para executar a sincronização bidirecional entre as réplicas.

SyncFileSystemReplicasOneWay(replica1RootPath, replica2RootPath, null, options);
SyncFileSystemReplicasOneWay(replica2RootPath, replica1RootPath, null, options);
public static void SyncFileSystemReplicasOneWay(
        string sourceReplicaRootPath, string destinationReplicaRootPath,
        FileSyncScopeFilter filter, FileSyncOptions options)
{
    FileSyncProvider sourceProvider = null;
    FileSyncProvider destinationProvider = null;

    try
    {
        // Instantiate source and destination providers, with a null filter (the filter
        // was specified in DetectChangesOnFileSystemReplica()), and options for both.
        sourceProvider = new FileSyncProvider(
            sourceReplicaRootPath, filter, options);
        destinationProvider = new FileSyncProvider(
            destinationReplicaRootPath, filter, options);

        // Register event handlers so that we can write information
        // to the console.
        destinationProvider.AppliedChange +=
            new EventHandler<AppliedChangeEventArgs>(OnAppliedChange);
        destinationProvider.SkippedChange +=
            new EventHandler<SkippedChangeEventArgs>(OnSkippedChange);

        // Use SyncCallbacks for conflicting items.
        SyncCallbacks destinationCallbacks = destinationProvider.DestinationCallbacks;
        destinationCallbacks.ItemConflicting += new EventHandler<ItemConflictingEventArgs>(OnItemConflicting);
        destinationCallbacks.ItemConstraint += new EventHandler<ItemConstraintEventArgs>(OnItemConstraint);

        SyncOrchestrator agent = new SyncOrchestrator();
        agent.LocalProvider = sourceProvider;
        agent.RemoteProvider = destinationProvider;
        agent.Direction = SyncDirectionOrder.Upload; // Upload changes from the source to the destination.

        Console.WriteLine("Synchronizing changes to replica: " +
            destinationProvider.RootDirectoryPath);
        agent.Synchronize();
    }
    finally
    {
        // Release resources.
        if (sourceProvider != null) sourceProvider.Dispose();
        if (destinationProvider != null) destinationProvider.Dispose();
    }
}
SyncFileSystemReplicasOneWay(replica1RootPath, replica2RootPath, Nothing, options)
SyncFileSystemReplicasOneWay(replica2RootPath, replica1RootPath, Nothing, options)
Public Shared Sub SyncFileSystemReplicasOneWay(ByVal sourceReplicaRootPath As String, _
                                               ByVal destinationReplicaRootPath As String, ByVal filter As FileSyncScopeFilter, _
                                               ByVal options As FileSyncOptions)

    Dim sourceProvider As FileSyncProvider = Nothing
    Dim destinationProvider As FileSyncProvider = Nothing

    Try
        ' Instantiate source and destination providers, with a null filter (the filter
        ' was specified in DetectChangesOnFileSystemReplica()), and options for both.
        sourceProvider = New FileSyncProvider(sourceReplicaRootPath, filter, options)
        destinationProvider = New FileSyncProvider(destinationReplicaRootPath, filter, options)

        ' Register event handlers so that we can write information 
        ' to the console. 
        AddHandler destinationProvider.AppliedChange, AddressOf OnAppliedChange
        AddHandler destinationProvider.SkippedChange, AddressOf OnSkippedChange

        ' Use SyncCallbacks for conflicting items.
        Dim destinationCallbacks As SyncCallbacks = destinationProvider.DestinationCallbacks
        AddHandler destinationCallbacks.ItemConflicting, AddressOf OnItemConflicting
        AddHandler destinationCallbacks.ItemConstraint, AddressOf OnItemConstraint

        Dim agent As New SyncOrchestrator()
        agent.LocalProvider = sourceProvider
        agent.RemoteProvider = destinationProvider
        agent.Direction = SyncDirectionOrder.Upload
        ' Upload changes from the source to the destination. 
        Console.WriteLine("Synchronizing changes to replica: " & destinationProvider.RootDirectoryPath)
        agent.Synchronize()
    Finally
        ' Release resources. 
        If sourceProvider IsNot Nothing Then
            sourceProvider.Dispose()
        End If
        If destinationProvider IsNot Nothing Then
            destinationProvider.Dispose()
        End If
    End Try
End Sub

Exemplo de código completo

O código a seguir é o código completo deste exemplo. Os exemplos anteriores nesta seção foram tirados deste código. Para executar este código:

  • Crie um projeto de aplicativo de console e adicione o código ao projeto.

  • Adicione referências a Microsoft.Synchronzation.dll e Microsoft.Synchronzation.Files.dll.

  • Crie o projeto para criar um executável.

  • Execute o executável na linha de comando para sincronizar os arquivos e subdiretórios de dois diretórios de réplica: MyExeName.exe \path\to\directoryA \path\to\directoryB.

using System;
using System.IO;
using Microsoft.Synchronization;
using Microsoft.Synchronization.Files;

namespace Microsoft.Samples.Synchronization
{
    class Program
    {
        public static void Main(string[] args)
        {
            if (args.Length < 2 ||
                string.IsNullOrEmpty(args[0]) || string.IsNullOrEmpty(args[1]) ||
                !Directory.Exists(args[0]) || !Directory.Exists(args[1]))
            {
                Console.WriteLine(
                  "Usage: MyExecutableName.exe [valid directory path 1] [valid directory path 2]");
                return;
            }

            string replica1RootPath = args[0];
            string replica2RootPath = args[1];

            try
            {
                // Set options for the synchronization session. In this case, options specify
                // that the application will explicitly call FileSyncProvider.DetectChanges, and
                // that items should be moved to the Recycle Bin instead of being permanently deleted.
                FileSyncOptions options = FileSyncOptions.ExplicitDetectChanges |
                         FileSyncOptions.RecycleDeletedFiles | FileSyncOptions.RecyclePreviousFileOnUpdates | 
                         FileSyncOptions.RecycleConflictLoserFiles;

                // Create a filter that excludes all *.lnk files. The same filter should be used 
                // by both providers.
                FileSyncScopeFilter filter = new FileSyncScopeFilter();
                filter.FileNameExcludes.Add("*.lnk");

                // Explicitly detect changes on both replicas before syncyhronization occurs.
                // This avoids two change detection passes for the bidirectional synchronization 
                // that we will perform.
                DetectChangesOnFileSystemReplica(
                    replica1RootPath, filter, options);
                DetectChangesOnFileSystemReplica(
                    replica2RootPath, filter, options);

                // Synchronize the replicas in both directions. In the first session replica 1 is
                // the source, and in the second session replica 2 is the source. The third parameter
                // (the filter value) is null because the filter is specified in DetectChangesOnFileSystemReplica().
                SyncFileSystemReplicasOneWay(replica1RootPath, replica2RootPath, null, options);
                SyncFileSystemReplicasOneWay(replica2RootPath, replica1RootPath, null, options);
            }
            catch (Exception e)
            {
                Console.WriteLine("\nException from File Sync Provider:\n" + e.ToString());
            }
        }

        // Create a provider, and detect changes on the replica that the provider
        // represents.
        public static void DetectChangesOnFileSystemReplica(
                string replicaRootPath,
                FileSyncScopeFilter filter, FileSyncOptions options)
        {
            FileSyncProvider provider = null;

            try
            {
                provider = new FileSyncProvider(replicaRootPath, filter, options);
                provider.DetectChanges();
            }
            finally
            {
                // Release resources.
                if (provider != null)
                    provider.Dispose();
            }
        }

        public static void SyncFileSystemReplicasOneWay(
                string sourceReplicaRootPath, string destinationReplicaRootPath,
                FileSyncScopeFilter filter, FileSyncOptions options)
        {
            FileSyncProvider sourceProvider = null;
            FileSyncProvider destinationProvider = null;

            try
            {
                // Instantiate source and destination providers, with a null filter (the filter
                // was specified in DetectChangesOnFileSystemReplica()), and options for both.
                sourceProvider = new FileSyncProvider(
                    sourceReplicaRootPath, filter, options);
                destinationProvider = new FileSyncProvider(
                    destinationReplicaRootPath, filter, options);

                // Register event handlers so that we can write information
                // to the console.
                destinationProvider.AppliedChange +=
                    new EventHandler<AppliedChangeEventArgs>(OnAppliedChange);
                destinationProvider.SkippedChange +=
                    new EventHandler<SkippedChangeEventArgs>(OnSkippedChange);

                // Use SyncCallbacks for conflicting items.
                SyncCallbacks destinationCallbacks = destinationProvider.DestinationCallbacks;
                destinationCallbacks.ItemConflicting += new EventHandler<ItemConflictingEventArgs>(OnItemConflicting);
                destinationCallbacks.ItemConstraint += new EventHandler<ItemConstraintEventArgs>(OnItemConstraint);

                SyncOrchestrator agent = new SyncOrchestrator();
                agent.LocalProvider = sourceProvider;
                agent.RemoteProvider = destinationProvider;
                agent.Direction = SyncDirectionOrder.Upload; // Upload changes from the source to the destination.

                Console.WriteLine("Synchronizing changes to replica: " +
                    destinationProvider.RootDirectoryPath);
                agent.Synchronize();
            }
            finally
            {
                // Release resources.
                if (sourceProvider != null) sourceProvider.Dispose();
                if (destinationProvider != null) destinationProvider.Dispose();
            }
        }

        // Provide information about files that were affected by the synchronization session.
        public static void OnAppliedChange(object sender, AppliedChangeEventArgs args)
        {
            switch (args.ChangeType)
            {
                case ChangeType.Create:
                    Console.WriteLine("-- Applied CREATE for file " + args.NewFilePath);
                    break;
                case ChangeType.Delete:
                    Console.WriteLine("-- Applied DELETE for file " + args.OldFilePath);
                    break;
                case ChangeType.Update:
                    Console.WriteLine("-- Applied OVERWRITE for file " + args.OldFilePath);
                    break;
                case ChangeType.Rename:
                    Console.WriteLine("-- Applied RENAME for file " + args.OldFilePath +
                                      " as " + args.NewFilePath);
                    break;
            }
        }

        // Provide error information for any changes that were skipped.
        public static void OnSkippedChange(object sender, SkippedChangeEventArgs args)
        {
            Console.WriteLine("-- Skipped applying " + args.ChangeType.ToString().ToUpper()
                  + " for " + (!string.IsNullOrEmpty(args.CurrentFilePath) ?
                                args.CurrentFilePath : args.NewFilePath) + " due to error");

            if (args.Exception != null)
                Console.WriteLine("   [" + args.Exception.Message + "]");
        }

        // By default, conflicts are resolved in favor of the last writer. In this example,
        // the change from the source in the first session (replica 1), will always
        // win the conflict.
        public static void OnItemConflicting(object sender, ItemConflictingEventArgs args)
        {
            args.SetResolutionAction(ConflictResolutionAction.SourceWins);
            Console.WriteLine("-- Concurrency conflict detected for item " + args.DestinationChange.ItemId.ToString());
        }

        public static void OnItemConstraint(object sender, ItemConstraintEventArgs args)
        {
            args.SetResolutionAction(ConstraintConflictResolutionAction.SourceWins);
            Console.WriteLine("-- Constraint conflict detected for item " + args.DestinationChange.ItemId.ToString());
        }
    }
}

No exemplo Visual Basic, o código define explicitamente o atributo MTAThread no método Main(). O provedor de sincronização de arquivos exige que os aplicativos usem o modelo de threading MTA (Multi-Threaded Apartment).

Imports System
Imports System.IO
Imports Microsoft.Synchronization
Imports Microsoft.Synchronization.Files

Namespace Microsoft.Samples.Synchronization

    Class Program

        ' File synchronization provider requires applications to use the multithreaded apartment (MTA) 
        ' threading model. This is specified by using the MTAThread attribute.
        <MTAThreadAttribute()> _
        Public Shared Sub Main(ByVal args As String())
            If args.Length < 2 OrElse String.IsNullOrEmpty(args(0)) OrElse String.IsNullOrEmpty(args(1)) OrElse Not Directory.Exists(args(0)) OrElse Not Directory.Exists(args(1)) Then
                Console.WriteLine("Usage: MyExecutableName.exe [valid directory path 1] [valid directory path 2]")
                Exit Sub
            End If

            Dim replica1RootPath As String = args(0)
            Dim replica2RootPath As String = args(1)

            Try
                ' Set options for the synchronization session. In this case, options specify 
                ' that the application will explicitly call FileSyncProvider.DetectChanges, and 
                ' that items should be moved to the Recycle Bin instead of being permanently deleted. 
                Dim options As FileSyncOptions = _
                    FileSyncOptions.ExplicitDetectChanges Or FileSyncOptions.RecycleDeletedFiles _
                    Or FileSyncOptions.RecyclePreviousFileOnUpdates _
                    Or FileSyncOptions.RecycleConflictLoserFiles

                ' Create a filter that excludes all *.lnk files. The same filter should be used 
                ' by both providers.
                Dim filter As New FileSyncScopeFilter()
                filter.FileNameExcludes.Add("*.lnk")

                ' Explicitly detect changes on both replicas before syncyhronization occurs. 
                ' This avoids two change detection passes for the bidirectional synchronization 
                ' that we will perform. 
                DetectChangesOnFileSystemReplica(replica1RootPath, filter, options)
                DetectChangesOnFileSystemReplica(replica2RootPath, filter, options)

                ' Synchronize the replicas in both directions. In the first session replica 1 is 
                ' the source, and in the second session replica 2 is the source. The third parameter
                ' (the filter value) is null because the filter is specified in DetectChangesOnFileSystemReplica().
                SyncFileSystemReplicasOneWay(replica1RootPath, replica2RootPath, Nothing, options)
                SyncFileSystemReplicasOneWay(replica2RootPath, replica1RootPath, Nothing, options)
            Catch e As Exception
                Console.WriteLine(vbLf & "Exception from File Sync Provider:" & vbLf & e.ToString())
            End Try
        End Sub

        ' Create a provider, and detect changes on the replica that the provider 
        ' represents. 
        Public Shared Sub DetectChangesOnFileSystemReplica(ByVal replicaRootPath As String, ByVal filter As FileSyncScopeFilter, _
                                                           ByVal options As FileSyncOptions)
            Dim provider As FileSyncProvider = Nothing

            Try
                provider = New FileSyncProvider(replicaRootPath, filter, options)
                provider.DetectChanges()
            Finally
                ' Release resources. 
                If provider IsNot Nothing Then
                    provider.Dispose()
                End If
            End Try
        End Sub

        Public Shared Sub SyncFileSystemReplicasOneWay(ByVal sourceReplicaRootPath As String, _
                                                       ByVal destinationReplicaRootPath As String, ByVal filter As FileSyncScopeFilter, _
                                                       ByVal options As FileSyncOptions)

            Dim sourceProvider As FileSyncProvider = Nothing
            Dim destinationProvider As FileSyncProvider = Nothing

            Try
                ' Instantiate source and destination providers, with a null filter (the filter
                ' was specified in DetectChangesOnFileSystemReplica()), and options for both.
                sourceProvider = New FileSyncProvider(sourceReplicaRootPath, filter, options)
                destinationProvider = New FileSyncProvider(destinationReplicaRootPath, filter, options)

                ' Register event handlers so that we can write information 
                ' to the console. 
                AddHandler destinationProvider.AppliedChange, AddressOf OnAppliedChange
                AddHandler destinationProvider.SkippedChange, AddressOf OnSkippedChange

                ' Use SyncCallbacks for conflicting items.
                Dim destinationCallbacks As SyncCallbacks = destinationProvider.DestinationCallbacks
                AddHandler destinationCallbacks.ItemConflicting, AddressOf OnItemConflicting
                AddHandler destinationCallbacks.ItemConstraint, AddressOf OnItemConstraint

                Dim agent As New SyncOrchestrator()
                agent.LocalProvider = sourceProvider
                agent.RemoteProvider = destinationProvider
                agent.Direction = SyncDirectionOrder.Upload
                ' Upload changes from the source to the destination. 
                Console.WriteLine("Synchronizing changes to replica: " & destinationProvider.RootDirectoryPath)
                agent.Synchronize()
            Finally
                ' Release resources. 
                If sourceProvider IsNot Nothing Then
                    sourceProvider.Dispose()
                End If
                If destinationProvider IsNot Nothing Then
                    destinationProvider.Dispose()
                End If
            End Try
        End Sub

        ' Provide information about files that were affected by the synchronization session. 
        Public Shared Sub OnAppliedChange(ByVal sender As Object, ByVal args As AppliedChangeEventArgs)
            Select Case args.ChangeType
                Case ChangeType.Create
                    Console.WriteLine("-- Applied CREATE for file " & args.NewFilePath)
                    Exit Select
                Case ChangeType.Delete
                    Console.WriteLine("-- Applied DELETE for file " & args.OldFilePath)
                    Exit Select
                Case ChangeType.Update
                    Console.WriteLine("-- Applied OVERWRITE for file " & args.OldFilePath)
                    Exit Select
                Case ChangeType.Rename
                    Console.WriteLine(("-- Applied RENAME for file " & args.OldFilePath & " as ") & args.NewFilePath)
                    Exit Select
            End Select
        End Sub

        ' Provide error information for any changes that were skipped. 
        Public Shared Sub OnSkippedChange(ByVal sender As Object, ByVal args As SkippedChangeEventArgs)
            Console.WriteLine(("-- Skipped applying " & args.ChangeType.ToString().ToUpper() & " for ") & (If(Not String.IsNullOrEmpty(args.CurrentFilePath), args.CurrentFilePath, args.NewFilePath)) & " due to error")

            If args.Exception IsNot Nothing Then
                Console.WriteLine(" [" & args.Exception.Message & "]")
            End If
        End Sub

        ' By default, conflicts are resolved in favor of the last writer. In this example, 
        ' the change from the source in the first session (replica 1), will always 
        ' win the conflict. 
        Public Shared Sub OnItemConflicting(ByVal sender As Object, ByVal args As ItemConflictingEventArgs)
            args.SetResolutionAction(ConflictResolutionAction.SourceWins)
            Console.WriteLine("-- Concurrency conflict detected for item " & args.DestinationChange.ItemId.ToString())
        End Sub

        Public Shared Sub OnItemConstraint(ByVal sender As Object, ByVal args As ItemConstraintEventArgs)
            args.SetResolutionAction(ConstraintConflictResolutionAction.SourceWins)
            Console.WriteLine("-- Constraint conflict detected for item " & args.DestinationChange.ItemId.ToString())
        End Sub
    End Class
End Namespace

Consulte também

Referência

Microsoft.Synchronization.Files

Conceitos

Sincronizando arquivos