如何配置 N 层同步
本主题演示如何为 Sync Framework 配置 N 层同步。本主题中的示例着重介绍以下 Sync Framework 类型:
有关如何运行示例代码的信息,请参见对常见客户端与服务器同步任务进行编程中的“帮助主题中的示例应用程序”。
了解 N 层同步
在 N 层同步体系结构中,同步组件分布在多个层中,如下图所示。
在双层体系结构中,所有组件都驻留在客户端上,客户端直接与服务器通信。在 N 层体系结构中,服务器同步提供程序驻留在服务器或其他层上,层与层之间的通信由 ServerSyncProviderProxy 对象和服务(如 Windows Communication Foundation (WCF) 服务)处理。Sync Framework 的优点之一是可以轻松地将代码从双层体系结构移动到 N 层体系结构。如果代码构造适当,在创建服务并添加代理之后,仅需对同步代理代码进行少量变更。客户端和服务器同步提供程序不需要变更。
示例
下面的代码示例演示 N 层体系结构所涉及的主要组件。还需要其他 WCF 组件。如果您使用 Visual Studio 2008,会自动为您生成这些组件。有关更多信息,请参见 Visual Studio 文档。
API 的要点
本节提供的代码示例演示了双层同步和 N 层同步之间的相似之处,并指出了在配置 N 层同步时要使用的 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)
下面的代码示例创建客户端提供程序和服务器提供程序。无论使用双层体系结构还是 N 层体系结构,此代码都是相同的。
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