1. Understanding Data Synchronization Service Requirements
A Data Synchronization Service
is a Web service. Like any Web service, it is accessible via a URL and
contains a class of functionality whose methods can be invoked via a Web
protocol. The standard for Data Synchronization Services, that is, the
interface definition specified by the .NET Framework, mandates only four
methods.
ApplyChanges:
Receive all changes that have occurred on the client since the last
exchange of data (i.e., since the last synchronization) and apply them
on the server.
GetChanges:
Retrieve all changes that have been made by other uses on the server
since the last synchronization and deliver them to the client.
GetSchema:
Retrieve schema information regarding the tables that participate in
the synchronization from the server and deliver it to the client.
GetServerInfo:
Retrieve the name and description of the tables that participate in the
synchronization from the server and deliver them to the client.
Normally, the service combines the first two methods in the preceding list into a single method call named Synchronize.
Although few in number, these methods represent an extensive amount of functionality, for implied in ApplyChanges and GetChanges
is concurrency conflict detection. That is, the service must work in
conjunction with the client application and the server-side data store
to detect whether the client is attempting change data that was modified
on the server by some other user as it was being modified on the
client. Furthermore, the service should give the client a choice between
the following.
The modification of the row does not occur and the client is so notified.
The modification of the row does occur at the server, regardless of the impact on the changes made by the other user.
The second option is often referred to as “Last updater wins,” but “Forced update” is a more correct phrase.
For a data
store to be able to provide concurrency conflict detection, it must be
able to track changes. Any data store that is to be used by a Data
Synchronization Service must be able to do this. SQL Server CE 3.5 SP1
and SQL Server 2008 have a built-in change tracking capability that was
designed with Data Synchronization Services support as a requirement.
SQL Server 2005, on the other hand, has no built-in change tracking
support.
This is a less than
ideal solution. Moving the application’s back-end component to a new
server means running the scripts at the new server (and possibly running
the undo scripts at the old server). Many of you have probably added
some form of change tracking to a SQL Server database in support of an
application that you have developed and have encountered similar
database maintenance overhead. In our upcoming sample, we will use SQL
Server 2005 as our server-side data store. This will allow us to see the
Designer-generated SQL code and the impact that it has on the Northwind
database.
Interestingly, the change tracking needed for Data Synchronization Services does not require that a before and after
image of a modified row be maintained; only that the time and user of
the modification be tracked. The image of a deleted row, however, must
be maintained in the database. If the client submits, and is determined
to force acceptance of, an update of a row that was concurrently deleted
at the server, that row first must be undeleted at the server and then
the client’s update applied. This can happen only if the deleted row is
still available at the server. Rows that have been deleted from one
table are normally maintained in a separate table that is referred to as
the tombstone version of the original table.
Given this background
information, we can begin development of our own Data Synchronization
Service and a .NET Compact Framework application that will be a client
of that service.
2. Building a Data Synchronization Service
For our Data Synchronization Service we’ll implement a very simple example; one that updates some of the Customers
of the Northwind database. We develop our service, and its client
application, through a specific sequence of steps. Not only is this
sequence probably the easiest way to do the development, but it also
helps to illustrate the nature of a Data Synchronization Service and its
relationship to the .NET Compact Framework client application.
Specifically, we will do the following.
1. | Create
a Visual Studio 2008 solution that contains a Windows Communication
Foundation (WCF) Service Library project and a Smart Device project. The
former will evolve into our Data Synchronization Service; the latter
will be our client application.
|
2. | Use
the Sync Services Designer Wizard to generate code, some of which will
be inserted in the service application and some into the client
application. Most importantly, the code that is inserted into the client
application will talk to two synchronization providers: one that
connects to SQL Server CE on the device and one that connects to the
server-side data store.
|
3. | Modify
and complete the service application. Some of the changes we must make,
such as specifying the URL, are applicable to any Data Synchronization
Service; others, such as the Web binding to be used, will make the
service accessible to a mobile device client.
|
4. | Once
the service definition is complete, turn to our client project and add a
Web reference to that service, thus generating proxy code in our client
application. This code, also, will need to be modified, mainly because
it will contain class definitions that we do not want; class definitions
that conflict with definitions that are already in the Framework Class
Library.
|
5. | Once our client has the correct code for accessing the service, add the core functionality of our application.
|
Let us begin.
Note: Required Software
Before
starting development of a Data Synchronization Service and its
consuming Smart Device client application, ensure that you have the
necessary software on your development machine. You’ll need Visual
Studio 2008 SP1 or later for development. You will also need Microsoft
Synchronization Services SP1 (Devices) or later. (Support for desktop
clients comes with Visual Studio 2008, but for .NET Compact Framework
clients you will need this separate download.) For the server-side data
store, SQL Server 2005 or later is needed; SQL Server 2008 makes life
easier; an Express version of either will do just fine. And lastly, for
the client-side data store you’ll need SQL Server CE 3.5 SP1 or later.
2.1. Beginning Development of Both Projects
We begin the actual development by creating a solution, named DataSyncDemo, containing two projects: a Visual C# / WCF / WCF Service Library project named SyncClnt and a Visual C# / Smart Device / Smart Device Project / Device Application named SyncServ. Figure 1 shows the resulting Solution Explorer window.
As we can see from Figure 1,
we have a device application with a default form defined and a service
application with a default WCF Service and contract defined. These last
two are of no use to us, and we will delete them shortly. What we want
is not a WCF Service but rather a Data Synchronization Service. To have
Visual Studio generate the starter code for us, we need to invoke the
Configure Data Synchronization Wizard. To do that, we need to add a
Local Data Cache item to our project.
“Which project?” you ask.
Normally, it would not matter which project, for the wizard will
generate code into both projects, which is why we needed
both projects to be in the same solution. Whenever you are adding a
Local Data Cache item, keep the following in mind: A Local Data Cache
item consists of both server-side and client-side components. It is
easiest if you think of yourself as adding the Local Data Cache to the
entire solution, not to a single project within that solution.
In actuality, the term Local Data Cache is misleading. It is not a memory-resident cache such as the Web application Cache
object is, for its data is maintained in a SQL Server CE database. It
is not just data, for it includes the components necessary to
synchronize that data with the back-end data store. And although it
resides on the local device, it is frequently communicating with the
server and bringing data that originated on the server down to the
device. Perhaps the best name would be the class name of its keystone
object, SyncAgent.
In our situation it
does matter to which project we try to add the Local Data Cache, for
Smart Device projects do not provide you the option of adding a Local
Data Cache item. Therefore, we must add a new Local Data Cache item to
the service project, as shown in Figure 2.
This will result in the appearance of the Configure Data Synchronization Wizard, shown in Figure 3.
First, we make our Server Connection selection to choose the connection
to the server database. You probably have a data source connection
already defined within your development environment for the target
database. If so, select it; if not, select New and create one. Once we
have made our selection, the Client Connection drop down and the Add
button become enabled. We can either select a client connection or have a
new one created for us. If we select New, the wizard will not ask us
for further information; it knows where the client-side database will be
located, on the device, and it knows that it will be a SQL Server CE
database. The wizard will simply generate the code to create and use a
SQL Server CE database file on the device.
The “Use SQL
Server change tracking” option is disabled because we chose a SQL Server
2005 database rather than a SQL Server 2008 database. Since SQL Server
2005 does not have built-in change tracking, the option is disabled.
If the selected SQL Server
2005 database has not had the necessary scripts run against it to
create a change tracking capability, the word “(New)” will appear next
to the choices in the Server Location drop downs. If this is the case,
when we finish using the wizard, it will generate SQL scripts and
display a dialog asking us whether we want the scripts run now and where
we want them stored.
If asked, the
wizard will modify the selected Northwind database, adding/altering the
tables and triggers necessary to provide a change tracking capability
sufficient for use with a Data Synchronization Service.
Click on the Advanced
chevron and you will be able to tell the wizard that you want code
generated for both the service and the client. Be sure to select the
correct projects in the Server Project and Client Project drop downs.
When you have done this you should be in the state shown in Figure 3.
At this point, we can
click on the Add button and begin to specify which server-side tables
will participate in the synchronization and provide some information
about how the rows of each are to be synchronized, as shown in Figure 4.
When
we click OK twice to dismiss both dialog boxes, the Designer adds some
references and writes some code into both projects. We cannot see what
that code is yet, for a new dialog box has appeared; but some of the
newly added code relates to the addition of the earlier mentioned SQL
Server CE database file onto our device store. Since the wizard is
providing for the storage of data on the client, why is the new dialog
box (see Figure 5)
offering to include a data set on the client as well? The answer is,
because data tables are data-bindable, whereas a database is not.
The wizard is merely offering to include an ADO.NET typed data set in
your client project so that you can more easily display synchronized
data to the user by moving it from the SQL Server CE database into a
data set and then binding the data tables to controls.
The
fact that this dialog is presented as part of adding a new Local Data
Cache item to the Data Synchronization Services project hides the fact
that the data set will be added to the client project, not to the Data
Synchronization Services project. Always remember, a Local Data Cache
item consists of both service components and client components.
We’ll accept the offer of
a typed data set in our device client application and dismiss the
dialog. A look at the Solution Explorer window, shown in Figure 6, reveals that much has been added to our projects.
On the client side, references to two Microsoft.Synchronization libraries have been added. The SynchProvider and SynchAgent classes (more on these in a minute) have been added into CustCache.Client.sync.
Also added to the client project is the SQL Server CE database file and
the ADO.NET typed data set. What has not been added is the proxy code
necessary for calling the service. This cannot be done at this time
because we have not yet finished developing the service; therefore, a
Web reference to the service cannot be set, and therefore the proxy
cannot be generated.
The SynchProvider and SynchAgent
classes that are defined in the newly added
CustCache.Client.Designer.cs file know how the data is to be
synchronized and where it is located on the device, for we provided that
information to the wizard. What they do not know is what Data
Synchronization Service will be used. That will not be known until we
have completed the service project, run it, and set a client project Web
reference to it. In other words, the SynchProvider and SynchAgent classes will work in conjunction with the to-be-written Proxy class to synchronize data between device and server. In production, if the service is moved to a different server, the SynchProvider and SynchAgent classes will remain unchanged; the Proxy class, or at least its URL property, will need to be updated.
At this
point, the Configure Data Synchronization Wizard has written as much
skeleton code as it can. We need to finish developing the service and
then complete the client.