Enhance Your Multi-tier Applications with the Windows Communication Foundation

n the previous articles in this series, you received a primer on the Windows Communication Foundation, before moving on to look at the fundamental aspects of the framework insofar as security, transactability, and reliability were concerned. The logical next step is to look at an example of a real-world system (albeit cut down for brevity) that demonstrates these principals in practice.

A typical real-world system is built on an n-tier architecture; each tier has a specific role to play. Typically, when an application developer is implementing these tiers, they have to spend considerable time developing many of the non-business logic aspects of the tier, such as reliability, transactability and security. Each of these are fundamental aspects of the Windows Communication Foundation that developers can quickly and easily implement, thus letting them spend more time implementing business logic.

Figure 1 shows a typical four-tier architecture. At the top is the resource tier, usually involving a database or similar information engine. Directly beneath this is a data-access layer (DAL) that abstracts access to the raw resource layer. This abstraction strengthens architectures, removing the brittleness that is associated with tightly bound resource tiers. If, for example, the middleware or front end layer of your application is tightly bound to SQL Server 2000, upgrading to SQL Server 2005 may involve tinkering with a existing code that contains your core business logic. Using a DAL, however, a service abstracts the database behind it. A Web service is an implementation-independent abstract entity that defines its underlying logic. WCF services are no different. Therefore, it makes a lot of sense to abstract the resource tier behind a Web service; and if you ever need to change the resource tier, you would simply create a new service that binds to the same contract as the original, and all of the business logic that is “underneath” the Web service?namely your core business and presentation logic will be unaffected.

?
Figure 1. Application Tiers: The figure shows desirable characteristics for each tier in a typical four-tier application design.

Configuration, Configuration, Configuration
When building an abstract interface to the data and resource layer reliability is key. Before the dawn of WCF, developers would have had to have written many hundreds, if not thousands of lines of code to ensure that the interface between the business logic and the data-access layers were reliable. Code to ensure that the payload was delivered accurately, in the correct order, without falsification is paramount. With WCF, you can concentrate on implementing your business logic, and let the framework handle the reliability concerns, based on standard WS-Reliability algorithms. You simply configure the endpoints of your service for reliability and the ServiceModel takes care of the rest. In many cases you’ll want this layer to be transactable too, safely handling large amounts of data. Again, in WCF you can handle transactability simply through configuration.

The presentation layer, in turn has to communicate with the business logic layer. In this case, security is important, as the presentation layer is exposed to many users, not all of whom you want to have accessing your core business logic. In the loosely coupled world of services, you would need to implement security algorithms by hand, or use technology such as WSE 3.0. With WCF, this is all abstracted away from you. You write your application to do what it needs to do, and security is handled for you in the ServiceModel. You simply need to configure it.

This article walks you through the process to build a very simple and lightweight application that exhibits the above architecture. You will see where, step by step, you can add security to the interface between presentation and business logic, and reliability between the business logic and data access. You’ll look at the SOAP messages being passed between them, and from here glean the raw power that is at your disposal when using the Windows Communication Foundation!

The Application: Resource Tier
The application is a simple request/response chat or bulletin board application. Hence the resource tier is a table in a database. In this case I’ve used SQL Server 2005. Here’s the script to build the table (it’s also in the downloadable sample code).

   USE [IndigoChat]   GO     /****** Object:  Table [dbo].[IndigoChat] ******/     /****** Script  Date: 02/08/2006 20:46:54 ******/   SET ANSI_NULLS ON   GO   SET QUOTED_IDENTIFIER ON   GO   CREATE TABLE [dbo].[IndigoChat](      [MsgID] [numeric](18, 0) IDENTITY(1,1) NOT NULL,      [MessageText] [nvarchar](max) COLLATE       SQL_Latin1_General_CP1_CI_AS NULL,      [MessageOwner] [nvarchar](max) COLLATE       SQL_Latin1_General_CP1_CI_AS NULL,      [MessageTimeStamp] [smalldatetime] NULL,         CONSTRAINT [PK_IndigoChat] PRIMARY KEY CLUSTERED       ([MsgID] ASC) WITH (IGNORE_DUP_KEY = OFF)       ON [PRIMARY])    ON [PRIMARY]

The preceding script creates a database table that contains an ID for the message, the text of the message, the name of the message owner and the timestamp when the message was sent. As this is a simple example, the message text is simply a large nVarChar data type, as is the author (Message Owner) of the message. In a real system this would be a lot more sophisticated?this is just to demonstrate the concepts.

?
Figure 2. Creating a New Service: The figure shows the dialog where you can elect to create a new Windows Communication Foundation Service.

The Application: Data-access Tier
The data-access tier is a Windows Communication Foundation service. If you’ve installed all the latest bits for WinFX, including the Visual Studio.NET add-ins, you’ll simple be able to click File?> New Web Site and get the dialog shown in Figure 2.

Author’s Note: The Windows Communication Foundation is part of WinFX, hence the terminology.

Electing to create a new WinFX service results in a new Visual Studio.NET project that contains a bunch of files. The ones that you are interested in initially are service.svc and its associated code file: service.cs, found in the App_Code directory.

The methods that you’ll implement on this new service are:

  • GetBackChat. This method reads all messages in the message archive after and including a specific message ID. When users connect to the chat system, their current state includes their most recently downloaded message ID. This function downloads the rest of the messages in the archive to them.
  • InsertMessage. This method allows a user to insert a new message.
  • GetMostRecentMessageID. This method gets the ID of the most recently posted message in the system. By comparing that ID to the most recent ID that users have in-state, you can determine whether they are up to date.

Remember that this service is part of the DAL that talks to the resource tier on behalf of the business logic. The client does not interface with the service directly. In this example, the InsertMessage function requires knowledge of who is sending the message. It is part of the functionality of the business logic tier to establish that identity. In a real-world situation, the business logic tier would do much more, for example, checking permissions to see if a specific user can actually write to the chat database or just read from it, or in a multi-room environment, determine which rooms a user can access.

The WCF-based data-access tier is implemented as a service, and thus the API needs a service contract. This contract is defined by the IChatResource interface and implemented by the ChatResource class as shown in Listing 1.

It is key that this layer must provide reliability. But as you can see in Listing 1, there is no code that implements any form of reliability. So how do you achieve it?

This is the magic of WCF. Reliability characteristics (along with Transactability and Security as you will see later) can be implemented declaratively, through configuration rather than in code. The ServiceModel handles the rest. As shown below, the data-access tier service gains its reliability characteristics because of the configuration settings in its Web.config file. The settings that establish the use of WS-Reliability are highlighted.

                                                                                                  

And that’s all it takes to implement WS-Reliability for this service. In the download you will find a text file (HttpSniff.txt) that contains sniffed HTTP packets for a session using this application. Check out the SOAP packets for communication between the business logic tier and the data-access tier and you will see WS-Reliability in action. Pretty neat, huh?

You can see these from section #15 onwards in the HttpSniff.txt file included in the downloadable code. You should also take a look at the schema declarations for http://schemas.xmlsoap.org/ws/2005/02/rm, which is the schema for WS-Reliable Messaging. This schema defines the soap tags with the “” prefix in the message, and if you compare these tags, such as or you’ll see that you are implementing the reliability specification without coding explicitly for it.

Here’s an example:

        urn:uuid:b6648b56-d4f8-427a-8fed-2b12db01462b         

The Application?Business Logic Tier
It is the responsibility of the business logic tier to provide the middleware in any system. This is a crucial layer, as it protects and enriches the back end data resources, as well as providing accessibility to the presentation layer that the user ultimately sees. In a typical scenario, the business logic layer integrates disparate data sources, and adds value to them through analytics or other functions. In a chat system, for example, the business logic layer would provide granular permissioning.

In this demonstration system, there appears to be little difference between the business logic layer and the data-access layer. The business logic layer does little more than perform a pass-through. This is actually quite a common practice?and a recommended one?because as requirements for application functionality grow, the layer separation is already in place, and the data-access tier would require little or no modification.

The business logic layer in this sample does handle establishing the secure identity of the client. Because this tier protects the database, any access to this layer should be sanitized, in other words, it should be accessible only by authenticated users. Security is paramount, so the system must ensure that users are who they say they are. In this example, the application assumes that users are already logged in to the corporate network; the client tier passes their corporate identity to the business logic tier. Thus, anyone without access to the corporate network would not be able to access this business logic. This is important not only for security, but also for the user experience; with this scheme, users don’t need a separate set of sign-in credentials to be able to access the Chat system, nor does the corporate administrator need to keep an eye on a completely different set of credential systems, exposing a larger attack surface.

Here’s the business logic tier code.

   [ServiceContract(Namespace=      "http://Devx.Indigo.Samples")]   public interface IChatService   {      [OperationContract]      string GetBackChat(int nMessageID);      [OperationContract]      bool InsertMessage(string strMsg);      [OperationContract]      decimal GetMostRecentMessageID();   }      public class ChatService : IChatService   {        public string GetBackChat(int nMessageID)       {         ChatResourceProxy chatResource = new             ChatResourceProxy();         return chatResource.GetBackChat(nMessageID);      }      public bool InsertMessage(string strMessage)      {         string strUserID =             Thread.CurrentPrincipal.Identity.Name;         ChatResourceProxy chatResource = new             ChatResourceProxy();         return chatResource.InsertMessage(            strUserID, strMessage);      }      public decimal GetMostRecentMessageID()      {         ChatResourceProxy chatResource = new             ChatResourceProxy();         return chatResource.GetMostRecentMessageID();      }   }

Note that, similar to the data-access tier, there’s no code written specifically for security in the preceding code. Also notice, as previously mentioned, that this code is largely pass through. One minor, but important difference is in the InsertMessage function. This function exposes a different footprint to the client?one that doesn’t expect the user identity to be passed in. (Compare it with the one in the data-access tier (see Listing 1) that does expect a user identity argument). In this case, to implement a secure system, you don’t want to expose the identity API to callers, thus giving them a chance to pass in fake credentials. You want the credentials to be managed by WS-Security APIs and not your own API.

The implementation of the InsertMessage function then pulls the user’s ID from the Thread.CurrentPrinicapal.Identity property. The ServiceModel provides the user’s ID to that method. How does it do this? Again, it’s declarative and not programmed. The Web.config for the business logic tier shows you how to accomplish this:

                                                                                  

Notice that the ChatService class shown earlier calls the data-access tier using a ChatResourceProxy object. This proxy is created automatically using the svcutil tool provided by WCF. When you create and implement a WCF service, it has an associated WSDL file. To create a client accessor, you simply run svcutil and pass it the location of the WSDL as a parameter. Doing that creates two files?a .cs file containing the proxy, and a file called Output.config containing the configuration that the ServiceModel needs to access the service. Simply add the contents of Output.config to your Web.config or App.config (the former if your client is a Web application, the latter if it is a WinForms application) and WCF will handle the communication for you.

The Application?Client Tier
The final level in your application is the client tier. In this example the client tier is a Windows Form, which uses a proxy generated by the svcutil tool to talk to the business logic tier. You can see it in action in Figure 3.

?
Figure 3. The Client Application: The figure shows how the running client application looks when viewing the chat data.

Note that the sender field contains the ID established when I sign into this network (called BookDev) and my personal credentials. This has all been handled for me by the ServiceModel and the proxy generated by svcutil when I specified that the service handles Windows Credentials in its Web.config (see the previous section).

This client uses the automatically generated proxy to read the back chat API, and then loads the resulting XML into a DataGridView as shown below:

   // Read the Back Chat API into a DataGridView control.   ChatServiceProxy chatProxy = new ChatServiceProxy();   string strBackChat = chatProxy.GetBackChat(1);   System.IO.StringReader xmlRead = new       System.IO.StringReader(strBackChat);   DataSet tmp = new DataSet();   tmp.ReadXml(xmlRead, XmlReadMode.Auto);   dataGridView1.DataSource = tmp;   dataGridView1.DataMember = "chatnode";   dataGridView1.Refresh();

You can easily expand this client to add a text box so users can type something, and have it call the InsertMessage proxy method, or to keep track of the state of the database using the GetMostRecentMessageID() method.

The Windows Communication Foundation adds major value to any multi-tier application development. By implementing your layers as services, and configuring them using the System.ServiceModel configuration in their Web.config files, you can concentrate on building your software logic, rather than on implementing the underlying plumbing to support security, reliability, transactions, and all the other functionality that enterprise-class applications require. This article showed a simple application that encompasses an n-tier architecture, illustrating how you can easily empower this architecture using the WCF service model, but already you should begin to see the raw power that WCF gives you. If you are considering or already involved in building connected systems and need security, reliability, interoperability, manageability, transactions, or any of the other typical capabilities of an enterprise system, I recommend that you begin exploring this framework to see just how much time and effort you can save.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: