AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=1597&pId=-1
Client Application Services - Part 3
page
by Bilal Haidar
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 35482/ 65

Overview

In part two of this series, we demonstrated the authentication and authorization by developing an ASP.NET 2.0 web application to host the ASP.NET 2.0 AJAX 1.0 Extensions Application Services. After that, we created a Windows client application that was enabled for authentication and authorization by setting the URL of the remote services.

In this last article of the series on Client Application Services, we will show you how to load and save Profile objects enabled on the ASP.NET host application by importing them to the Windows client application as Web user settings. In addition, we will configure the application to run offline, so that all the operations covering, authentication, authorization, and profile processing will be done against a local copy of the data.

Profile Service

ASP.NET 2.0 Application Services introduced Profile objects. As explained in part one of this series, Profile object holds data per user in an application. That data is stored inside the database and it is preserved for all visits.

To enable accessing those Profile objects in the Windows client application, there should be a way to tell the Windows client application where to load and where to save those Profile objects.

First of all, we will configure the ASP.NET host application to enable Profile service and add a few Profile objects that we will import later on to the Windows client application.

Start with adding the following XML configuration to the Web.config configuration file.

Listing 1

<system.web.extensions>
    <scripting>
      <webServices>
        <authenticationService enabled="true" requireSSL = "false"/>
        <roleService enabled="true"/>
        <profileService enabled="true"
          readAccessProperties="LastLoginDate,Back_Color"
          writeAccessProperties="LastLoginDate,Back_Color" />
      </webServices>
    </scripting>
</system.web.extensions>

The new section added in here is enabling the ASP.NET 2.0 AJAX 1.0 Extensions Profile service and configuring two Profile objects for read and writes by the client, whether the client is an AJAX or a Windows client application.

When the application is an AJAX one, a client-side proxy is created that points to the Profile_JSON_AppService.axd HttpHandler. This handler will execute on the server and access the Profile provider configured.

Once the ASP.NET 2.0 AJAX 1.0 Extensions application services are configured, the Profile service should also be enabled and configured as follows.

Listing 2

<profile enabled="true" >
      <properties>
        <add name="LastLoginDate" type="DateTime"
          readOnly="false" serializeAs="String" allowAnonymous="false" />
        <add name="Back_Color" type="System.String"
          readOnly="false" serializeAs="String" allowAnonymous="false" />
      </properties>
</profile>

This is a typical Profile service configuration for an ASP.NET 2.0 application. First of all, Profile service is enabled then two Profile objects were configured and added. Nothing new in here!

Web User Settings

Now that the Profile service has been enabled and configured on the ASP.NET host application it is time to configure the Windows client application to use that remote Profile service.

In Windows Forms, there has been a feature known as Application Settings. This feature allows you to store data per application and per user locally similar in a way to the concept of Application and Session variables in ASP.NET. The data in both cases is stored in XML files in the user’s local hard disk. The way to add those settings is by adding a special item to your application with the extension of .Settings. This item is nothing but an XML file with a nice UI designer that allows you to add settings that target both application and user settings. Once you add any settings to that file, a new instance of the Settings class is now accessible in your client application by using the Properties.Settings.Default. The Default object is the default instance of the Settings class which has a base class of ApplicationSettingsBase. All the settings you add to the Windows client application are automatically added as strongly typed properties to the Default object so that you can easily access them inside your code. For more information on Application Settings, follow this link: Application Settings Overview.

Going back to enabling the Profile service inside the Windows client application, Figure 1 below shows you how to add the URL of the remote Profile service at the Services tab of the client application.

Figure 1: Services Tab

As you can see in the figure above, the last section is the Web settings services. As mentioned in the above paragraph, there are Application and User settings, however, when accessing Profile service, what we will do is import all the Profile objects into the Windows client application and Visual Studio automatically imports the Profile objects as User settings with a special notation called Web settings. Therefore, Profile objects will be imported as Web User settings! To load those objects, first make sure you have configured the Web settings service location to the same URL where the Authentication and Authorization services are located. Client Application Services framework automatically appends the Profile_JSON_AppService.axd when the Profile objects are accessed. In the next step, create a new .Settings file in your Windows application, open it, and then press on the Load Web Settings button on the top toolbar as shown in Figure 2 below.

Figure 2: Loading Web user settings

By pressing on the Load Web Settings, you will notice two new user settings were created for you. Those user settings were loaded from the Profile service configuration on the ASP.NET host application. This step is necessary before you can work with the Web user settings.

The Web user settings are now loaded and ready to be accessed by your application to read from and write to.

Now back to the Windows client main application Form_Load event, we will issue a call to a method called BindWebSettings that will retrieve the Web user settings and bind their values on the main form as follows.

Listing 3

private void BindWebSettings()
{
  try
  {
    // Add binding to the last login date
    this.lblLastLoginDate.DataBindings.Add("Text", Properties.Settings.Default,
      "LastLoginDate");
 
    // Set the background color to the one stored in the application settings
    if (string.IsNullOrEmpty((Properties.Settings.Default.Back_Color)))
      Properties.Settings.Default.Back_Color = "#909090";
 
    this.BackColor = System.Drawing.ColorTranslator.FromHtml(
      (Properties.Settings.Default.Back_Color));
  }
  catch (System.Net.WebException)
  {
    MessageBox.Show("Unable to access the Web Settings service.""Warning",
      MessageBoxButtons.OK, MessageBoxIcon.Warning);
  }
}

As you can see, working with Web user settings is no different than working with normal application settings. First of all, a binding is added to a label on the main form to show the last login date for the currently authenticated user. In addition, the color name stored in another Web user setting is converted to a real color and set to the main form’s background color.

A textbox is now placed on the main form with a label to allow the user to change the value of the Back_Color Web user setting. When the user clicks on that button, the code below executes to save the changes locally into the remote Profile service as follows.

Listing 4

private void SaveSettings()
{
  if
    (!System.Threading.Thread.CurrentPrincipal.Identity.AuthenticationType.Equals(
      "ClientForms"))
    return ;
 
  try
  {
    Properties.Settings.Default.Save();
  }
  catch (System.Net.WebException ex)
  {
    // This means you are logged out
    if (ex.Message.Contains("You must log on to call this method."))
    {
      MessageBox.Show(
        "Your session has expired. Please login again to be able to save" +
        "your settings.""Saving Web Settings");
 
      try
      {
        // Show the Login form for the user to enter his/her credentials
        // to login again
        if (!Membership.ValidateUser(String.Empty, String.Empty))
        {
          MessageBox.Show("Unable to authenticate. " +
            "Settings were not saved on the remote service.""Not logged in",
            MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        else
        {
          // Try again saving the settings
          // after the user has been authenticated
          SaveSettings();
        }
      }
      catch (System.Net.WebException)
      {
        MessageBox.Show("Unable to access the authentication service. " +
          "Settings were not saved on the remote service.""Not logged in",
          MessageBoxButtons.OK, MessageBoxIcon.Warning);
      }
    }
    else
    {
      MessageBox.Show("Unable to access the Web settings service. " +
        "Settings were not saved on the remote service.""Not logged in",
        MessageBoxButtons.OK, MessageBoxIcon.Warning);
    }
  }
}

As you can see, some checking is added to make sure the user is logged in using the ClientForms authentication type. The Save method, defined on the ApplicationBaseSettings base class, is executed to save the Web user settings locally into the remote Profile service. If the user was not logged in, the Login form pops up to allow the user to enter his/her credentials again to be authenticated before being able to save the Web user setting remotely.

Finally, to make sure we are on the safe side, we have subscribed to the Form_Closing event to make sure a call to save the Web user settings is present. If the user, by mistake or intentionally, closed the main application, we have to make sure the Web user settings are saved back to the remote Profile service successfully.

Running in Offline mode

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.

Downloads
References

Material is still scarce on this topic, but there is a very informative section on the MSDN library that allows you to get an idea on all the details the surrounds Client Application Services. Follow this link to access this information: Client Application Services.

Conclusion

In this article we have shown you how to access the Profile service configured on the ASP.NET host application from inside the Windows client application. The Profile objects are loaded as Web user settings into the Windows client application.

In addition, the article explained in details how to put the Windows client application to run in the Offline mode and how to move the application back to the live mode by authenticating the user silently, saving any offline changes to the Web user settings, and refreshing the Web user settings from the Profile service.

Finally, a Logout feature was implemented to show you how easily it is to add a logout button and use the ClientFormsAuthenticationMembershipProvider to logout the user and save any pending changes on the Web user settings.

This was the last article in the series of articles on the Client Application Service. We hope you enjoyed this article and benefited from the information presented. If you have any questions or comments please feel free to contact me directly at bhaidar@gmail.com.

Happy Ajaxified Dot Netting!!!



©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-26 9:26:14 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search