饭饭TXT > 学习管理 > 《Visual Studio 2010 高级编程(英文出书版)》作者:Nick Randolph/等【完结】 > [Visual.Studio.2010.高级编程].Professional.Visual.Studio.2010.txt

第 111 页

作者:Nick Randolph/等 当前章节:15375 字 更新时间:2026-6-18 14:51

Caching box, as shown in Figure 34-5.

Now when you select Next you are presented

with a new step in the wizard that allows you

to configure the way that data is synchronized

between the server and your local database

cache. In Figure 34-6 you can see that for

each table you can toggle the synchronization

mode between Incremental and Snapshot.

The former is better for tables that contain

a large quantity of data that changes

frequently; the latter is for tables that contain

small reference sets that change infrequently

and don’t require change tracking.

The other option presented in Figure 34-6 is whether to enable SQL Server change tracking. Sync

Services relies on being able to track changes to the data in order to synchronize those changes

between the server and the client. Out of the box it supports two mechanisms for doing this. You

can either enable change tracking, in which case changes on the server are automatically tracked by

the SQL Server database, or you can configure Sync Services to track changes within your database

fiGure 34-5

fiGure 34-6

750 .

chaPter 34 SynchronizATion SerViceS

tables. The former is only available with SQL Server 2008, and the latter requires additional fields,

triggers, and tables in order to provide equivalent change tracking capabilities. If you are going to be

deploying the database to SQL Server 2008, it is recommended that you enable change tracking.

When you click Finish you are prompted to confirm that you want to apply the server changes

immediately (Figure 34-7). If you’re working on a database shared by others, you may want

to review the generated scripts before allowing them to execute. For this example leave both

checkboxes checked, which will create the database scripts (including undo scripts) and add them

to your project, as well as execute them on the server database, to either enable change tracking

or to create the additional change tracking columns, triggers, and tables.

Clicking OK both persists this configuration in the form of synchronization classes and invokes a

synchronization between the server and the local data file, as shown in Figure 34-8.

fiGure 34-7 fiGure 34-8

Forcing synchronization at this point means that the newly created SQL Server Compact (SSC)

database file is populated with the correct schema and any data available on the server. The

LocalCRMDataSet is also added to your project.

If you now look at the Data Sources tool window, you will see that there is a LocalCRMDataSet

node that contains a Customer node. As you did previously, set the Customer node to Details and

the CustomerId node to None. Then drag the Customer node across onto the designer surface of the

LocalForm. The result should be a form similar to the one shown in Figure 34-9.

fiGure 34-9

synchronization services over n-Tiers .

751

Adding these components brings the same components to the design surface and the same code

to the form as when you were connecting directly to the server. The difference here is that a

CustomerTableAdapter connects to the local database instead of the server. As before, you need

to add the code to specify the CustomerId for new records in the CurrentChanged event of the

CustomerBindingSource.

The last thing you need to add to this part of the project is a mechanism to invoke the synchronization

process. Simply add a button, SynchronizeButton, to the bottom of the LocalForm and double-click

it to generate the click-event handler. Then add the following code to trigger a synchronization.

Vb

Private Sub SynchronizeButton_Click(ByVal sender As System.Object,

ByVal e As System.EventArgs)

Handles SynchronizeButton.Click

Dim syncAgent As New CRMCacheSyncAgent()

Dim syncStats As Microsoft.Synchronization.Data.SyncStatistics =

syncAgent.Synchronize()

Me.CustomerTableAdapter.Fill(Me.LocalCRMDataSet.Customer)

End Sub

Code snippet LocalForm.vb

c#

private void SynchronizeButton_Click(object sender, EventArgs e){

var syncAgent = new CRMCacheSyncAgent();

var syncStats = syncAgent.Synchronize();

this.customerTableAdapter.Fill(this.localCRMDataSet.Customer);

}

Code snippet LocalForm.cs

Pay particular attention to the next-to-last line of this snippet, in which you use the

CustomerTableAdapter to fill the Customer table. This is important: without this line the user

interface will not reflect changes in the SSC database that have been made by the synchronization

process.

synchronization serVices oVer n-tiers

So far, the entire synchronization process is conducted within the client application with a direct

connection to the server. One of the objectives of an occasionally connected application is to be

able to synchronize data over any connection, regardless of whether it is a corporate intranet or the

public Internet. Unfortunately, with the current application you need to expose your SQL Server so

that the application can connect to it. This is clearly a security vulnerability, which you can solve by

taking a more distributed approach. Sync Services has been designed with this in mind, allowing the

server components to be isolated into a service that can be called during synchronization.

752 .

chaPter 34 SynchronizATion SerViceS

Sync Services supports separating the synchronization process so that the client application

communicates via a WCF service, instead of directly to the server database. To do this, you need to

create a WCF service that implements the four methods that makes up Sync Service, as shown in the

following IServiceCRMCacheSyncContract interface.

Vb

<ServiceContractAttribute()> _

Public Interface IServiceCRMCacheSyncContract

<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

The WCF Service essentially acts as a remote proxy for the server provider used by Sync Service. To use

the WCF Service, you first need to add it to the client project using Add Service Reference (right-click

your project and select this option from the context menu). Then you need to set the Remote Provider

on the Sync Agent to be a new instance of the ServerSyncProviderProxy. The constructor for the

ServerSyncProviderProxy class takes a single parameter which should be the proxy class that was

generated for the WCF Service using Add Service Reference. Now, when you call Synchronize, Sync

Services will use the Remote Provider to call the methods on the WCF Service. The WCF Service will in

turn communicate with the server database carrying out the synchronization logic.

backGround synchronization

You may have noticed that when you click the synchronize button, the user interface appears to

hang until the synchronization completes. Clearly this wouldn’t be acceptable in a real-world

application, so you need to synchronize the data in the background, thereby allowing the user to

continue working. By adding a BackgroundWorker component (in the Components group in the

Toolbox) to the LocalForm, you can do this with only minimal changes to your application. The

following code illustrates how you can wire up the events of the BackgroundWorker, which has been

named bgWorker, to use the Sync Service implementation. This makes use of an additional button,

SynchronizeInBackgroundButton, that was added to the LocalForm:

Vb

Private Sub SynchronizeInBackgroundButton_Click(ByVal sender As System.Object,

ByVal e As System.EventArgs) _

Handles SynchronizeInBackgroundButton.Click

Me.SynchronizeButton.Enabled = False

Me.SynchronizeInBackgroundButton.Enabled = False

Background synchronization .

753

Me.bgWorker.RunWorkerAsync(New CRMCacheSyncAgent())

End Sub

Private Sub bgWorker_DoWork(ByVal sender As System.Object,

ByVal e As System.ComponentModel.DoWorkEventArgs) _

Handles bgWorker.DoWork

Dim syncAgent As Microsoft.Synchronization.SyncAgent =

TryCast(e.Argument, Microsoft.Synchronization.SyncAgent)

If syncAgent Is Nothing Then Return

syncAgent.Synchronize()

End Sub

Private Sub bgWorker_RunWorkerCompleted(ByVal sender As System.Object, _

ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _

Handles bgWorker.RunWorkerCompleted

Me.CustomerTableAdapter.Fill(Me.LocalCRMDataSet.Customer)

Me.SynchronizeInBackgroundButton.Enabled = True

Me.SynchronizeButton.Enabled = True

End Sub

Code snippet LocalForm.vb

c#

private void SynchronizeInBackgroundButton_Click(object sender, EventArgs e){

this.SynchronizeButton.Enabled =false;

this.SynchronizeInBackgroundButton.Enabled = false;

this.bgWorker.RunWorkerAsync(new CRMCacheSyncAgent());

}

private void bgWorker_DoWork(object sender, DoWorkEventArgs e){

var syncAgent = e.Argument as Microsoft.Synchronization.SyncAgent;

if (syncAgent == null) return;

syncAgent.Synchronize();

}

private void bgWorker_RunWorkerCompleted(object sender,

RunWorkerCompletedEventArgs e){

this.customerTableAdapter.Fill(this.localCRMDataSet.Customer);

this.SynchronizeInBackgroundButton.Enabled = true;

this.SynchronizeButton.Enabled = true;

}

Code snippet LocalForm.cs

In this snippet you are not reporting any progress, but Sync Services does support quite a rich event

model that you can hook into in order to report on progress. If you want to report progress via the

BackgroundWorker component, you need to enable its WorkerReportsProgress property. The

following code illustrates how you can hook into the ApplyChanges event on the client component

754 .

chaPter 34 SynchronizATion SerViceS

of Sync Services in order to report progress (in this case to a label called “SyncProgressLabel” added

to the form). Other events correspond to different points in the synchronization process.

Vb

Private Sub bgWorker_DoWork(ByVal sender As System.Object, _

ByVal e As System.ComponentModel.DoWorkEventArgs) _

Handles bgWorker.DoWork

Dim syncAgent As Microsoft.Synchronization.SyncAgent = _

TryCast(e.Argument, Microsoft.Synchronization.SyncAgent)

If syncAgent Is Nothing Then Return

Dim clientProvider As _

Microsoft.Synchronization.Data.SqlServerCe.SqlCeClientSyncProvider = _

CType(syncAgent.LocalProvider, _

Microsoft.Synchronization.Data.SqlServerCe.SqlCeClientSyncProvider)

AddHandler clientProvider.SyncProgress, AddressOf SyncProgress

syncAgent.Synchronize()

End Sub

Private Sub SyncProgress(ByVal sender As Object, _

ByVal e As Microsoft.Synchronization.Data. SyncProgressEventArgs)

Dim progress = 0

If (e.GroupProgress.TotalChanges > 0) Then

progress = (e.GroupProgress.TotalChanges -

e.GroupProgress.TotalChangesPending) _

* 100 / e.GroupProgress.TotalChanges

End If

Me.bgWorker.ReportProgress(progress, e.SyncStage.ToString())

End Sub

Private Sub bgWorker_ProgressChanged(ByVal sender As Object, _

ByVal e As System.ComponentModel.ProgressChangedEventArgs) _

Handles bgWorker.ProgressChanged

Me.SyncProgressLabel.Text = e.UserState.ToString

End Sub

Code snippet LocalForm.vb

c#

private void bgWorker_DoWork(object sender, DoWorkEventArgs e){

var syncAgent = e.Argument as Microsoft.Synchronization.SyncAgent;

if (syncAgent == null) return;

var clientProvider = syncAgent.LocalProvider as

Microsoft.Synchronization.Data.SqlServerCe.SqlCeClientSyncProvider;

clientProvider.SyncProgress += SyncProgress;

syncAgent.Synchronize();

}

private void SyncProgress(object sender,

Microsoft.Synchronization.Data.SyncProgressEventArgs e){

var progress = 0;

if(e.GroupProgress.TotalChanges>0){

progress = (e.GroupProgress.TotalChanges -

e.GroupProgress.TotalChangesPending)

Client Changes .

755

*100 /e.GroupProgress.TotalChanges;

}

this.bgWorker.ReportProgress(progress, e.SyncStage.ToString());

}

private void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e){

this.SyncProgressLabel.Text = e.UserState.ToString();

}

Code snippet LocalForm.cs

client chanGes

Working through the example so far, you may have been wondering why none of the changes you

have made on the client are being synchronized to the server. If you go back to Figure 34-6, you

will recall that you selected Incremental from the top drop-down, which might lead you to believe

that changes from both the client and server will be synchronized. This is not the case and it is the

wording above this control that gives it away. For whatever reason, this control only enables you to

select options pertaining to “Data to download.” To get changes to propagate in both directions,

you have to override the default behavior for each table that is going to be synchronized. Again,

right-click the CRMCache object in the Solution Explorer and select View Code. In the following

code, we have set the SyncDirection property of the CustomerSyncTable to be bidirectional. You

may also want to do this for the ServerCRMCache item so that both synchronization mechanisms

will allow changes to propagate between client and server.

Vb

Partial Public Class CRMCacheSyncAgent

Partial Class CustomerS yncTable

Private Sub OnInitialized()

Me.SyncDirection = _

Microsoft.Synchronization.Data.SyncDirection.Bidirectional

End Sub

End Class

End Class

CRMCache.vb

c#

partial class CRMCacheSyncAgent{

partial class CustomerSyncTable{

private void OnInitialized(){

this.SyncDirection =

Microsoft.Synchronization.Data.SyncDirection.Bidirectional;

目录
设置
设置
阅读主题
字体风格
雅黑 宋体 楷书 卡通
字体大小
适中 偏大 超大
保存设置
恢复默认
手机
手机阅读
扫码获取链接,使用浏览器打开
书架同步,随时随地,手机阅读
首 页 < 上一章 章节列表 下一章 > 尾 页