N 層同期を構成する方法
このトピックでは、Sync Framework 向けに N 層同期を構成する方法について説明します。このトピックの例では、次に示す Sync Framework の型を中心に説明します。
サンプル コードを実行する方法については、「一般的なクライアントとサーバーの同期タスクのプログラミング」の「操作方法に関するトピックのサンプル アプリケーション」を参照してください。
N 層同期について
N 層同期アーキテクチャでは、次の図に示すように、同期コンポーネントが複数層にまたがって分散されています。
2 層アーキテクチャでは、すべてのコンポーネントがクライアント上に存在し、クライアントはサーバーと直接通信します。一方、N 層アーキテクチャでは、サーバー同期プロバイダーがサーバーまたは別の層に存在し、層間の通信は、Windows Communication Foundation (WCF) サービスなどのサービスと ServerSyncProviderProxy オブジェクトによって処理されます。Sync Framework のメリットの 1 つは、2 層アーキテクチャから N 層アーキテクチャに簡単にコードを移行できることです。コードに必要な要素を含め、不要な要素を除外するプロセスが適切に行われている場合、サービスの作成とプロキシの追加が完了した後は、同期エージェント コードを少し変更するだけで済みます。クライアントとサーバーの同期プロバイダーを変更する必要はありません。
例
次のコード例は、N 層アーキテクチャに関連した主要コンポーネントを示しています。追加の WCF コンポーネントは必須です。Visual Studio 2008 を使用している場合、これらのコンポーネントは自動的に生成されます。詳細については、Visual Studio のマニュアルを参照してください。
API の主要部分
このセクションでは、2 層同期と N 層同期の共通点を表したコード例を示し、N 層同期を構成する際に使用する API の主要部分について述べます。次のコード例では、SyncAgent から派生するクラスを示します。2 層同期では、クライアント プロバイダーとサーバー プロバイダーはローカル プロバイダーおよびリモート プロバイダーとして同期エージェントで直接両方が参照されます。
this.LocalProvider = new SampleClientSyncProvider();
this.RemoteProvider = new SampleServerSyncProvider();
Me.LocalProvider = New SampleClientSyncProvider()
Me.RemoteProvider = New SampleServerSyncProvider()
2 層の例として、クライアント プロバイダーを直接参照するコード例を次に示します。ただし、リモート プロバイダーはサーバー プロバイダーを直接参照する代わりにプロキシを参照します。プロキシは、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)
次のコード例では、クライアントとサーバーのプロバイダーを作成します。このコードは、2 層と 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
次のコード例では、サービスによって実装されるインターフェイスを作成します。このインターフェイスには、サーバー プロバイダーの 4 つの主要メソッドが用意されています。
[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