information. Because this timeout determines the maximum period it will take for role changes
to be propagated to a connected client, it is important that you set this property according to how
frequently you expect role information to change. Clearly, if the application is running offline, the
changes will be retrieved the next time the application goes online (assuming the cache timeout has
been exceeded while the application is offline).
Clicking the Save Password Hash checkbox means that the application doesn’t have to be online for the
user to log in. The stored password hash is used only when the application is running in offline mode,
in contrast to the role information, for which the cache is queried unless the timeout has been exceeded.
Whether the application is online or offline is a property maintained by the client application
services, because it is completely independent of actual network or server availability. Depending on
your application, it might be appropriate to link the two as shown in the following example, where
offline status is set during application startup or when the network status changes. From the project
properties designer, click the View Application Events button on the Application tab (VB), or open
App.xaml and add an event handler for the Startup event. This displays a code file in which the
following code can be inserted:
c#
using System.Net.NetworkInformation;
public partial class App : Application{
private void Application_Startup(object sender, StartupEventArgs e){
NetworkChange.NetworkAvailabilityChanged +=
new NetworkAvailabilityChangedEventHandler
(NetworkChange_NetworkAvailabilityChanged);
this.UpdateConnectivity();
}
private void NetworkChange_NetworkAvailabilityChanged(object sender,
NetworkAvailabilityEventArgs e){
this.UpdateConnectivity();
}
private void UpdateConnectivity(){
System.Web.ClientServices.ConnectivityStatus.IsOffline =
!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
}
}
Code snippet Application.xaml.cs
Vb
Class Application
Private Sub MyApplication_Startup(ByVal sender As Object,
ByVal e As System.Windows.StartupEventArgs) Handles Me.Startup
AddHandler System.Net.NetworkInformation.NetworkChange.
NetworkAvailabilityChanged, _
AddressOf MyApplication_NetworkAvailabilityChanged
UpdateConnectivity()
End Sub
742 .
chaPter 33 clienT ApplicATion SerViceS
Private Sub MyApplication_NetworkAvailabilityChanged(
ByVal sender As Object,
ByVal e As System.Net.NetworkInformation.NetworkAvailabilityEventArgs)
UpdateConnectivity()
End Sub
Private Sub UpdateConnectivity()
System.Web.ClientServices.ConnectivityStatus.IsOffline = Not _
My.Computer.Network.IsAvailable()
End Sub
End Class
Code snippet Application.xaml.vb
You should note that this is a very rudimentary way of detecting whether an application is online,
and that most applications require more complex logic to determine if they are, in fact, connected.
The other thing to consider is that when the application comes back online, you may wish to
confirm that the user information is still up to date using the RevalidateUser method on the
ClientFormsIdentity object (only relevant to Forms authentication):
c#
(System.Threading.Thread.CurrentPrincipal.Identity as
System.Web.ClientServices.ClientFormsIdentity).RevalidateUser()
Vb
CType(System.Threading.Thread.CurrentPrincipal.Identity,
System.Web.ClientServices.ClientFormsIdentity).RevalidateUser()
The last property in the Advanced dialog determines where the cached credential and role
information is stored. This checkbox has been enabled because we chose to use Windows
authentication earlier in the example. If you are using Forms authentication you can clear this
checkbox. The client application services will use .clientdata files to store per-user data under
the Application.UserAppDataPath, which is usually something like C:\Users\Nick\AppData\
Roaming\ClientServices\1.0.0.0 (this will differ on Windows XP). Using a custom connection
string enables you to use a SQL Server Compact Edition (SSCE) database file to store the credentials
information. This is required for offline support of Windows authentication.
Unfortunately, the designer is limited in that it doesn’t enable you to specify any
existing connections you may have. If you modify the app.config file, you can
tweak the application to use the same connection.
This might be a blessing in disguise, because the |SQL/CE| datasource property
(which is the default) actually lets the client application services manage the
creation and setup of the SSCE database file (otherwise you have to ensure that
the appropriate tables exist).
You will notice that the files that are created are .spf instead of the usual .sdf
file extension — they are still SSCE database files that you can explore with
Visual Studio 2010.
summary .
743
suMMary
In this chapter, you have seen how the ASP.NET Application Services can be extended for use with
client applications. With built-in support for offline functionality, the client application services
enable you to build applications that can seamlessly move between online and offline modes.
Combined with the Microsoft ADO.NET Synchronization Services, they provide the necessary
infrastructure to build quite sophisticated occasionally connected applications.
34
synchronization services
what’s in this chaPter?
.
What an occasionally connected application is and why you would
build an application that way
.
Wiring up Synchronization Services to build an occasionally
connected application
.
Separating Synchronization Services across multiple tiers
.
Performing both single and bi-directional synchronization
Application design has gone through many extremes, ranging from standalone applications
that don’t share data, to public web applications in which everyone connects to the same
data store. More recently, we have seen a fl urry of peer-to-peer applications in which
information is shared between nodes but no central data store exists. In the enterprise
space, key buzzwords such as Software as a Service (SaaS) and Software and Services (S+S)
highlight the transition from centralized data stores, through an era of outsourced data and
application services, toward a hybrid model where data and services are combined within a
rich application.
One of the reasons organizations have leaned toward web applications in the past has
been the need to rationalize their data into a single central repository. Although rich client
applications can work well across a low-latency network using the same data repository,
they quickly become unusable if every action requires data to be communicated between the
client and server over a slow public network. To reduce this latency, an alternative strategy
is to synchronize a portion of the data repository to the client machine and to make local
data requests. This will not only improve performance, because all the data requests happen
locally, but it will also reduce the load on the server. In this chapter, you discover how
building applications that are only occasionally connected can help you deliver rich and
responsive applications using the Microsoft Synchronization Services for ADO.NET.
746 .
chaPter 34 SynchronizATion SerViceS
occasionally connected aPPlications
An occasionally connected application is one that can continue to operate regardless of connectivity
status. You have a number of different ways to access data when the application is offline. Passive
systems simply cache data that is accessed from the server, so that when the connection is lost
at least a subset of the information is available. Unfortunately, this strategy means that a very
limited set of data is available and is really only suitable for scenarios where there is an unstable
or unreliable connection, rather than completely disconnected applications. In the latter case, an
active system that synchronizes data to the local system is required. The Microsoft Synchronization
Services for ADO.NET (Sync Services) is a synchronization framework that dramatically simplifies
the problem of synchronizing data from any server to the local system.
serVer direct
To get familiar with the Sync Services, you will use a simple database that consists of a single table
that tracks customers. You can create this using the Server Explorer within Visual Studio 2010.
Right-click the Data Connections node and select Create New SQL Server Database from the
shortcut menu. Figure 34-1 shows the Create New SQL Server Database dialog in which you can
specify a server and a name for the new database.
When you click OK, a database with the name CRM is added to the SQL Server Express instance
and a data connection is added to the Data Connections node in the Server Explorer. From the
Tables node, under the newly created data connection, select Add New Table from the right-click
shortcut menu and create columns for CustomerId (primary key), Name, Email, and Phone so that
the table matches what is shown in Figure 34-2.
fiGure 34-1 fiGure 34-2
Now that you have a simple database to work with, it’s time to create a new Windows Forms
Application. In this case the application is titled QuickCRM, and in the Solution Explorer tool
window of Figure 34-3 you can see that we have renamed Form1 to MainForm and added two
additional forms, ServerForm and LocalForm.
server Direct .
747
fiGure 34-3
MainForm has two buttons, as shown in the editor area of Figure 34-3, and has the following code
to launch the appropriate forms:
Vb
Public Class MainForm
Private Sub ServerButton_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) _
Handles ServerButton.Click
My.Forms.ServerForm.Show()
End Sub
Private Sub LocalButton_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) _
Handles LocalButton.Click
My.Forms.LocalForm.Show()
End Sub
End Class
Code snippet MainForm.vb
c#
public partial class MainForm : Form {
public MainForm(){
InitializeComponent();
}
private void ServerButton_Click(object sender, EventArgs e){
(new ServerForm()).ShowDialog();
}
private void LocalButton_Click(object sender, EventArgs e){
(new LocalForm()).ShowDialog();
}
}
Code snippet MainForm.cs
Before looking at how you can use Sync Services to work with local data, take a look at how
you might have built an always-connected, or server-bound, version. From the Data menu, select
748 .
chaPter 34 SynchronizATion SerViceS
Add New Data Source and step through the Data Source Configuration Wizard, selecting the
DataSet option, followed by the CRM database created earlier, saving the connection string to
the application configuration file, and adding the Customer table to the CRMDataSet.
Open the ServerForm designer by double-
clicking it in the Solution Explorer tool
window. If the Data Sources tool window is
not already visible, select Show Data Sources
from the Data menu. Using the drop-down
on the Customer node, select Details and
then select None from the CustomerId node.
Dragging the Customer node across onto the
design surface of the ServerForm adds
the appropriate controls so that you can
locate, edit, and save records to the Customer
table of the CRM database, as shown in
Figure 34-4.
You will recall from the table definition that the CustomerId can’t be null, so you need to ensure
that any new records are created with a new ID. To do this you tap into the CurrentChanged event
on the CustomerBindingSource object. You can access this either directly in the code-behind of
the ServerForm or by selecting CustomerBindingSource and finding the CurrentChanged event
in the Properties tool window.
Vb
Private Sub CustomerBindingSource_CurrentChanged _
(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles CustomerBindingSource.CurrentChanged
If Me.CustomerBindingSource.Current Is Nothing Then
Return
End If
Dim c As CRMDataSet.CustomerRow = CType(CType(Me.CustomerBindingSource.Current,
DataRowView).Row,CRMDataSet.CustomerRow)
If c.RowState = DataRowState.Detached Then
c.CustomerId = Guid.NewGuid
End If
End Sub
Code snippet ServerForm.vb
c#
private void customerBindingSource_CurrentChanged(object sender, EventArgs e){
if (this.customerBindingSource.Current == null){
return;
}
var c = (this.customerBindingSource.Current as DataRowView)
.Row as CRMDataSet.CustomerRow;
fiGure 34-4
Getting started with synchronization services .
749
if (c.RowState == DataRowState.Detached){
c.CustomerId = Guid.NewGuid();
}
}
Code snippet ServerForm.cs
This completes the part of the application that connects directly to the database to access the data.
You can run the application and verify that you can access data while the database is online. If the
database goes offline or the connection is lost, an exception is raised by the application when you
attempt to retrieve from the database or save new changes.
GettinG started with synchronization serVices
To get started with Sync Services you need to add a Local Database Cache item to your project. In
the past you would have done this via the Add New Item dialog. However, in Visual Studio 2010
you can do this using the same process as you
would for adding a data source that connects
to a SQL Server database. Run the Data
Source Configuration Wizard by selecting
Add New Data Source from either the Data
Sources tool window or the Data menu. Step
through the wizard specifying the connection
string and selecting the Customer table. On
what would normally be the final screen,
where you specify the name of the dataset to
be created, check the Enable Local Database