HOW TO:使用 Managed 程式碼同步處理檔案
本主題示範如何使用 Managed 語言 (如 C# 或 Visual Basic) 建立應用程式,該應用程式會使用 Sync Framework 檔案同步處理提供者來同步處理檔案和子資料夾。
本主題的範例將重點放在下列的 Sync Framework 型別:
了解檔案同步處理
Sync Framework 會實作同步處理提供者,可用來同步處理檔案系統上資料夾中所包含的檔案和子資料夾。此提供者會公開一些可設定的設定值,能夠更細緻地控制同步處理發生的確切方式,以及所同步處理的確切項目。若要在兩個資料夾之間進行同步處理,應用程式要完成下列基本步驟:
建立 FileSyncProvider 物件來代表每個資料夾。
傳遞兩個提供者給 SyncOrchestrator 物件,然後指定其中一個做為來源提供者,指定另一個做為目的地提供者。
呼叫 Synchronize 來啟動同步處理工作階段。
如需同步處理檔案的詳細資訊,請參閱同步處理檔案。
範例
本節的範例程式碼是來自一個同步處理兩個目錄 (包括這些目錄中的子目錄和檔案) 的主控台應用程式。範例程式碼會示範下列工作:
如何設定同步處理選項。
如何明確執行複寫的變更偵測。
如何指定篩選來控制同步處理中要包含的項目。
如何處理在同步處理期間可能發生的衝突。
如何同步處理兩個複寫。
在顯示這些程式碼範例之後,我們會包含應用程式的完整程式碼,好讓您可以建置及執行。
設定同步處理選項
FileSyncOptions 物件可讓您設定檔案同步處理的幾個選項,包括如何偵測變更以及是否在同步處理期間刪除項目或是將項目移到資源回收筒。下列程式碼範例會設定四個選項,其中的三個選項與項目刪除有關。ExplicitDetectChanges 選項表示,除非應用程式明確呼叫 DetectChanges,否則 Sync Framework 將不會執行變更偵測。下一節<執行變更偵測>將會進一步說明。
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
執行變更偵測
根據預設,每當呼叫 Synchronize 時,Sync Framework 都會在兩個複寫上執行變更偵測。變更偵測可讓 Sync Framework 判斷哪些項目應該從來源傳送到目的地以及哪些項目發生衝突 (如果有的話)。您可以藉由指定 ExplicitDetectChanges 來控制何時要執行變更偵測。下列程式碼範例會在 Synchronize 呼叫之前,呼叫每一個複寫的變更偵測。這個範例的用意是要說明 DetectChanges,但是它確實具備了傳遞一個變更偵測 (而不是兩個) 的優點,當您之後在應用程式中執行雙向同步處理時,將會發生兩個變更偵測。
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
指定靜態篩選
您可以設定靜態篩選,依名稱 (包括萬用字元名稱) 和屬性來排除檔案,也可以設定靜態篩選來排除整個子資料夾的內容。或者指定所要包含檔案名稱的明確清單 (包括萬用字元名稱)。若要包含在範圍內,檔案或資料夾必須通過所有篩選。例如,如果副檔名為 .txt 的所有檔案都排除在範圍之外,而明確包含於範圍中的檔案清單內指定了 MyFile.txt,則 MyFile.txt 將會因為副檔名為 .txt 而遭到排除。
下列程式碼範例會使用 FileSyncScopeFilter 物件,建立一個篩選來排除所有 *.lnk 檔案。篩選與篩選的建立提供者並沒有任何關聯性。若要將篩選連接到提供者,請將此篩選傳遞到 FileSyncProvider 的其中一個建構函式,或是設定 ScopeFilter 屬性。在範例應用程式中,我們會在 DetectChangesOnFileSystemReplica()
方法中進行這項處理,因為此篩選只與變更偵測有關。因為此篩選與提供者無關,所以每一個同步處理工作階段只應該建立一個篩選。提供者不應該使用不同的篩選,因為這樣可能會導致非聚合性的資料。
FileSyncScopeFilter filter = new FileSyncScopeFilter();
filter.FileNameExcludes.Add("*.lnk");
Dim filter As New FileSyncScopeFilter()
filter.FileNameExcludes.Add("*.lnk")
除了靜態篩選之外,您也可以處理由提供者所引發的事件,在同步處理期間排除檔案。如需詳細資訊,請參閱控制同步處理的檔案。
處理衝突
Sync Framework 會針對檔案和資料夾偵測及解決「並行衝突」(Concurrency Conflict) 和「條件約束衝突」(Constraint conflict)。從兩個複寫之間的上一次同步處理工作階段以來,在這兩個複寫上變更相同的項目時,就會發生並行衝突。如果將同名的檔案或資料夾加入至這兩個複寫中,將會發生條件約束衝突。解決衝突的方式是保留具有最新變更的檔案或資料夾,並刪除 (或移動) 具有較舊變更的檔案或資料夾。如果是檔案,您也可以選擇指定來源或目的地應該贏得衝突,不論先發生哪一項變更。下列程式碼範例會讓事件處理常式註冊 ItemConflicting 和 ItemConstraint 事件,您可透過 SyncCallbacks 物件來使用這兩個事件。呼叫的方法會在來源勝出的情況下解決所有衝突,並將資訊寫入主控台。
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
同步處理兩個複寫
在設定選項和篩選之後,應用程式會同步處理這兩個複寫,其方式是具現化 SyncOrchestrator 及呼叫 Synchronize 方法。下列程式碼範例會指定每一個複寫的提供者、設定選項、註冊事件處理常式、指定 Upload 的同步處理方向及呼叫 Synchronize。將會呼叫這個方法兩次,以便執行複寫之間的雙向同步處理。
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
完整的程式碼範例
下列程式碼是此範例的完整程式碼。本節中先前的範例都是取自此程式碼。若要執行這段程式碼:
建立主控台應用程式專案,並將這段程式碼加入此專案。
加入 Microsoft.Synchronzation.dll 和 Microsoft.Synchronzation.Files.dll 的參考。
建置專案來建立可執行檔。
從命令列執行可執行檔,同步處理兩個複寫目錄的檔案和子目錄:
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());
}
}
}
在 Visual Basic 範例中,這段程式碼會在 Main()
方法上明確設定 MTAThread
屬性。檔案同步處理提供者會要求應用程式使用多執行緒 Apartment (MTA) 執行緒模型。
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
請參閱
參考
Microsoft.Synchronization.Files