Как настроить многоуровневую синхронизацию
В этом разделе описана настройка многоуровневой синхронизации для Sync Framework. В примерах, приведенных в этом разделе, рассматриваются следующие типы служб Sync Framework:
Сведения о способах запуска образца кода см. в подразделе «Образцы приложений в разделах инструкций» раздела Программирование распространенных задач синхронизации клиента и сервера.
Основные сведения о многоуровневой синхронизации
В многоуровневой архитектуре синхронизации компоненты синхронизации распределены по нескольким уровням, как показано на следующем рисунке.
В двухуровневой архитектуре все компоненты находятся на клиенте, а клиент напрямую сообщается с сервером. В многоуровневой архитектуре служба синхронизации сервера располагается на сервере или на другом уровне, а связь между уровнями обслуживается объектом ServerSyncProviderProxy и такой службой, как Windows Communication Foundation (WCF). Одной из сильных сторон служб Sync Framework является простота переноса кода из двухуровневой архитектуры в многоуровневую. Если код соответствующим образом оформлен, после создания службы и добавления учетной записи-посредника потребуется лишь небольшое изменение в коде агента синхронизации. Клиентские и службы синхронизации сервера изменять не потребуется.
Пример
Следующий пример кода показывает основные компоненты многоуровневой архитектуры. Необходимы дополнительные компоненты WCF. Эти компоненты создаются при использовании Visual Studio 2008. Дополнительные сведения см. в документации к Visual Studio.
Ключевые элементы API-интерфейса
В этом разделе приведены примеры кода, демонстрирующие сходство между двухуровневой и многоуровневой синхронизацией, и отмечены ключевые элементы API-интерфейса, применяемые при настройке многоуровневой синхронизации. Следующий пример кода представляет собой класс, который является производным от класса SyncAgent. При двухуровневой синхронизации агент синхронизации ссылается на поставщик клиента и поставщик сервера непосредственно как на локального и удаленного поставщиков.
this.LocalProvider = new SampleClientSyncProvider();
this.RemoteProvider = new SampleServerSyncProvider();
Me.LocalProvider = New SampleClientSyncProvider()
Me.RemoteProvider = New SampleServerSyncProvider()
В следующем примере кода выполняется прямое обращение к поставщику клиента, как в двухуровневом сценарии. Однако удаленный поставщик теперь ссылается не на поставщик сервера, а на класс-посредник. Учетная запись-посредник создается путем передачи ссылки службе WCF.
this.LocalProvider = new SampleClientSyncProvider();
ServiceReference.ServiceForSyncClient serviceProxy = new ServiceReference.ServiceForSyncClient();
this.RemoteProvider = new ServerSyncProviderProxy(serviceProxy);
Me.LocalProvider = New SampleClientSyncProvider()
Dim serviceProxy As New ServiceReference.ServiceForSyncClient()
Me.RemoteProvider = New ServerSyncProviderProxy(serviceProxy)
Следующие примеры кода создают клиентских и серверных поставщиков. Данный код применим как в двухуровневой, так и в многоуровневой архитектуре.
public class SampleClientSyncProvider : SqlCeClientSyncProvider
{
public SampleClientSyncProvider()
{
//Specify a connection string for the sample client database.
Utility util = new Utility();
this.ConnectionString = util.ClientConnString;
}
}
public class SampleServerSyncProvider : DbServerSyncProvider
{
public SampleServerSyncProvider()
{
//Create a connection to the sample server database.
Utility util = new Utility();
SqlConnection serverConn = new SqlConnection(util.ServerConnString);
this.Connection = serverConn;
//Create a command to retrieve a new anchor value from
//the server.
SqlCommand selectNewAnchorCommand = new SqlCommand();
string newAnchorVariable = "@" + SyncSession.SyncNewReceivedAnchor;
selectNewAnchorCommand.CommandText = "SELECT " + newAnchorVariable + " = min_active_rowversion() - 1";
selectNewAnchorCommand.Parameters.Add(newAnchorVariable, SqlDbType.Timestamp);
selectNewAnchorCommand.Parameters[newAnchorVariable].Direction = ParameterDirection.Output;
selectNewAnchorCommand.Connection = serverConn;
this.SelectNewAnchorCommand = selectNewAnchorCommand;
//Create a SyncAdapter for the Customer table manually, or
//by using the SqlSyncAdapterBuilder as in the following
//code.
SqlSyncAdapterBuilder customerBuilder = new SqlSyncAdapterBuilder(serverConn);
customerBuilder.TableName = "Sales.Customer";
customerBuilder.TombstoneTableName = customerBuilder.TableName + "_Tombstone";
customerBuilder.SyncDirection = SyncDirection.DownloadOnly;
customerBuilder.CreationTrackingColumn = "InsertTimestamp";
customerBuilder.UpdateTrackingColumn = "UpdateTimestamp";
customerBuilder.DeletionTrackingColumn = "DeleteTimestamp";
SyncAdapter customerSyncAdapter = customerBuilder.ToSyncAdapter();
customerSyncAdapter.TableName = "Customer";
this.SyncAdapters.Add(customerSyncAdapter);
}
}
Public Class SampleClientSyncProvider
Inherits SqlCeClientSyncProvider
Public Sub New()
'Specify a connection string for the sample client database.
Dim util As New Utility()
Me.ConnectionString = util.ClientConnString
End Sub
End Class
Public Class SampleServerSyncProvider
Inherits DbServerSyncProvider
Public Sub New()
'Create a connection to the sample server database.
Dim util As New Utility()
Dim serverConn As New SqlConnection(util.ServerConnString)
Me.Connection = serverConn
'Create a command to retrieve a new anchor value from
'the server.
Dim selectNewAnchorCommand As New SqlCommand()
Dim newAnchorVariable As String = "@" + SyncSession.SyncNewReceivedAnchor
selectNewAnchorCommand.CommandText = "SELECT " + newAnchorVariable + " = min_active_rowversion() � 1"
selectNewAnchorCommand.Parameters.Add(newAnchorVariable, SqlDbType.Timestamp)
selectNewAnchorCommand.Parameters(newAnchorVariable).Direction = ParameterDirection.Output
selectNewAnchorCommand.Connection = serverConn
Me.SelectNewAnchorCommand = selectNewAnchorCommand
'Create a SyncAdapter for the Customer table manually, or
'by using the SqlSyncAdapterBuilder as in the following
'code.
Dim customerBuilder As New SqlSyncAdapterBuilder(serverConn)
customerBuilder.TableName = "Sales.Customer"
customerBuilder.TombstoneTableName = customerBuilder.TableName + "_Tombstone"
customerBuilder.SyncDirection = SyncDirection.DownloadOnly
customerBuilder.CreationTrackingColumn = "InsertTimestamp"
customerBuilder.UpdateTrackingColumn = "UpdateTimestamp"
customerBuilder.DeletionTrackingColumn = "DeleteTimestamp"
Dim customerSyncAdapter As SyncAdapter = customerBuilder.ToSyncAdapter()
customerSyncAdapter.TableName = "Customer"
Me.SyncAdapters.Add(customerSyncAdapter)
End Sub
End Class
Следующий пример кода создает интерфейс, который реализуется службой. Этот интерфейс включает четыре ключевых метода серверного поставщика.
[ServiceContract]
public interface IServiceForSync
{
[OperationContract()]
SyncContext ApplyChanges(SyncGroupMetadata groupMetadata, DataSet dataSet, SyncSession syncSession);
[OperationContract()]
SyncContext GetChanges(SyncGroupMetadata groupMetadata, SyncSession syncSession);
[OperationContract()]
SyncSchema GetSchema(Collection<string> tableNames, SyncSession syncSession);
[OperationContract()]
SyncServerInfo GetServerInfo(SyncSession syncSession);
}
<ServiceContract()> _
Public Interface IServiceForSync
<OperationContract()> _
Function ApplyChanges(ByVal groupMetadata As SyncGroupMetadata, ByVal dataSet As DataSet, ByVal syncSession As SyncSession) As SyncContext
<OperationContract()> _
Function GetChanges(ByVal groupMetadata As SyncGroupMetadata, ByVal syncSession As SyncSession) As SyncContext
<OperationContract()> _
Function GetSchema(ByVal tableNames As Collection(Of String), ByVal syncSession As SyncSession) As SyncSchema
<OperationContract()> _
Function GetServerInfo(ByVal syncSession As SyncSession) As SyncServerInfo
End Interface
В следующем примере кода создается служба. Эта служба реализует интерфейс, созданный в предыдущем примере кода, и ссылается на серверный поставщик.
public class ServiceForSync : IServiceForSync
{
private SampleServerSyncProvider _serverSyncProvider;
public ServiceForSync()
{
this._serverSyncProvider = new SampleServerSyncProvider();
}
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public virtual SyncContext ApplyChanges(SyncGroupMetadata groupMetadata, DataSet dataSet, SyncSession syncSession) {
return this._serverSyncProvider.ApplyChanges(groupMetadata, dataSet, syncSession);
}
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public virtual SyncContext GetChanges(SyncGroupMetadata groupMetadata, SyncSession syncSession) {
return this._serverSyncProvider.GetChanges(groupMetadata, syncSession);
}
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public virtual SyncSchema GetSchema(Collection<string> tableNames, SyncSession syncSession) {
return this._serverSyncProvider.GetSchema(tableNames, syncSession);
}
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public virtual SyncServerInfo GetServerInfo(SyncSession syncSession) {
return this._serverSyncProvider.GetServerInfo(syncSession);
}
}
Public Class ServiceForSync
Implements IServiceForSync
Private _serverSyncProvider As SampleServerSyncProvider
Public Sub New()
Me._serverSyncProvider = New SampleServerSyncProvider()
End Sub
<System.Diagnostics.DebuggerNonUserCodeAttribute()> _
Public Overridable Function ApplyChanges(ByVal groupMetadata As SyncGroupMetadata, ByVal dataSet As DataSet, ByVal syncSession As SyncSession) As SyncContext
Return Me._serverSyncProvider.ApplyChanges(groupMetadata, dataSet, syncSession)
End Function
<System.Diagnostics.DebuggerNonUserCodeAttribute()> _
Public Overridable Function GetChanges(ByVal groupMetadata As SyncGroupMetadata, ByVal syncSession As SyncSession) As SyncContext
Return Me._serverSyncProvider.GetChanges(groupMetadata, syncSession)
End Function
<System.Diagnostics.DebuggerNonUserCodeAttribute()> _
Public Overridable Function GetSchema(ByVal tableNames As Collection(Of String), ByVal syncSession As SyncSession) As SyncSchema
Return Me._serverSyncProvider.GetSchema(tableNames, syncSession)
End Function
<System.Diagnostics.DebuggerNonUserCodeAttribute()> _
Public Overridable Function GetServerInfo(ByVal syncSession As SyncSession) As SyncServerInfo
Return Me._serverSyncProvider.GetServerInfo(syncSession)
End Function
End Class
См. также
Другие ресурсы
Программирование распространенных задач синхронизации клиента и сервера