Client Application Services provides you with the means to
allow your application to run in an offline mode. What happens then is that, if
the user has to be authenticated or authorized or even access Web user
settings, all of this will be done locally.
You configure your client application to cache user related
information locally. Once the application starts and the user is authenticated
successfully, a local authentication cookie is created and the user password
and roles are all hashed and stored locally. If the user now decides to turn
the application to the Offline mode, successive requests to load roles or
access Web user settings will be authenticated and authorized against the local
hashed copy of the credentials stored.
To prepare the application to store user related information
locally, you should first click on the Advanced button located to the
bottom-right corner of the Services tab. A popup window pops up and is shown in
Figure 3.
Figure 3: Advanced window
As mentioned previously, to prepare the application for
Offline mode, you should check the option that says Save password hash locally
to enable offline login. This is very important to check incase the application
is to run in an Offline mode.
Another important option is the Role service cache timeout
which you should set for a long time incase you are planning to run the
application in an offline mode. If the user roles are changing most of the
time, it is recommended to set this value to a small one.
Finally, you have the choice in where to store the user
related information locally. With the configuration above, when the user logs
in to the application, a new SQL Server Compact Edition 2.5 will be created for
this specific user which stores inside it all the user related information.
If you leave User custom connection string unchecked, the
client application will store the authentication cookie together with the
hashed roles and passwords locally on the hard disk as XML files.
You can also specify a connection string to a normal SQL
Server database. This way, the user related data will be stored inside a normal
SQL Server database. Before doing so, you need to configure your database by
adding several data tables. The TSQL script for those tables is as follows.
Listing 5
CREATE TABLE ApplicationProperties (PropertyName nvarchar(256),
PropertyValue nvarchar(256))
CREATE TABLE UserProperties (PropertyName nvarchar(256),
PropertyValue nvarchar(256))
CREATE TABLE Roles (UserName nvarchar(256),
RoleName nvarchar(256))
CREATE TABLE Settings (PropertyName nvarchar(256),
PropertyStoredAs nvarchar(1), PropertyValue nvarchar(2048))
The above script adds several tables that are used to store
the user’s related data when the application is configured to store locally the
roles and hashed passwords so that the application can be run in an Offline
mode.
Back to the main application, we have added a checkbox to
allow the user to put the application in the Offline mode or back to the live
mode. Once the selection changes, we are handling that inside the code as
follows.
Listing 6
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
// Set the IsOffline property on the ConnectivityStatus
ConnectivityStatus.IsOffline = this.chkWorkOffline.Checked;
if (!ConnectivityStatus.IsOffline)
{
try
{
// Revalidate the user silently
ClientFormsIdentity user = (ClientFormsIdentity)
System.Threading.Thread.CurrentPrincipal.Identity;
user.RevalidateUser();
SaveSettings();
Properties.Settings.Default.Reload();
}
catch (System.Net.WebException)
{
MessageBox.Show("Unable to access the authentication service. " +
Environment.NewLine + "Application will be kept in offline mode.",
"Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
this.chkWorkOffline.Checked = true;
}
}
}
First of all, the code sets the ConnectivityStatus.IsOffline
property to the state of the Work Offline checkbox. This is an important step
to do to inform the Client Application Services that the application is now
running in an Offline mode.
If the user unchecks the Work Offline checkbox, the code
first revalidates the user silently using the locally stored user information.
Once the user is successfully authenticated, Web user settings are saved back to
the remote Profile service incase the user has changed any of the Web user
settings while the application was offline and also, the local Web user
settings’ values are refreshed from the remote Profile service incase someone
else from another application has changed any of the values.
The final main application form is shown in Figure 4.
Figure 4: Main application form
As you can see, the welcome message is showing on the left
side of the form together with the authentication type and the list of roles
the user belongs to.
In addition, the Back_Color Web user setting is used to
configure the background color of the main application form, the LastLoginData
Web user setting is displayed on the top right of the form, together with the
checkbox to allow the user to run the application in the offline mode, and finally,
a textbox that is used in case the user wants to change the value of the
Back_Color Web user settings.
Logout
If you look at Figure 4 above, you will notice a button to
the bottom-right corner of the main application form called Logout. This button
is mainly used to allow the user to logout from the application. Logging out
from the application causes the authentication cookie stored locally to be
deleted. The code behind this button is as follows.
Listing 7
private void btnLogout_Click(object sender, EventArgs e)
{
// Save the Web settings first
SaveSettings();
// Get an instance of the ClientFormsAuthenticationMembershipProvider
// to use the Logout function which is not present on Membership.Provider
ClientFormsAuthenticationMembershipProvider clientFormAuthProvider =
(ClientFormsAuthenticationMembershipProvider)Membership.Provider;
try
{
clientFormAuthProvider.Logout();
}
catch (System.Net.WebException ex)
{
MessageBox.Show("Unable to access the authentication service." +
Environment.NewLine + "Logging off locally only.", "Warning",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
ConnectivityStatus.IsOffline = true;
authProvider.Logout();
ConnectivityStatus.IsOffline = false;
}
The Web user settings are saved back to the remote Profile
service. Then an instance of the ClientFormsAuthenticationMembershipProvider is
retrieved from the Membership.Provider in order to call the Logout method on
the ClientFormsAuthenticationMembershipProvider instance. If the remote
authentication service is not available, the code puts the application in the
Offline mode, logs the user out from the Offline mode, and turns off the
Offline mode. This way, when the user tries to re-connect to the application
later, the application would required to authenticate the user against the live
connection and not against any locally stored user related data.