Coding in Tiers - Part II

Introduction

While the Part I article of this series demonstrated the use of an Automator class to auto populate Windows Forms; It just touched upon the concept of separating disparate code into multiple tiers. In this article, we will walkthrough a Account Registration application which will demonstrate reuse of code by conceptualizing some of the various tiers described in my previous article.

NOTE: The code snippets provided in this article are algorithmic bare bones of the actual code to reduce the article complexity. Readers should refer to the source code provided for more details. The source code provided is well documented and self explanatory.

The downloadable source code provided includes the example application. I am using Visual Studio .NET 2003 with Framework SDK 1.1 to create this example.

The Example Application Requirements

The ultimate goal of this exercise is to capture and store registration information via a user interface presented as a Windows Form or ASP.NET Web Form. The registration information consists of the following fields...

Username - The account username to be used for logging into the system (Required).

Password - The password that is associated with the Username (Required).

Street - The street address.

Country - The country of residence (Required).

The user will enter necessary information on the fields provided by the presentation interface and then click on a "Register" button to request for an account creation. The fields marked as Required are mandatory and have to be filled in. The username entered has to be unique for an account. If the username entered already exists, the user is notified by displaying an appropriate error message. The request for a new account will be declined if the above conditions are not met and the errors will be reported by the application via the user interface. If all the required conditions are met, the information entered will be stored in a persistent data store such as an RDBMS database. The user will be notified after being successfully registered into the system.

Defining the Tiers

Let us start by conceptualizing the various tiers to be defined for our application by analyzing the functional requirements. The Windows Form UI is created as a Windows Application (Win project) while the Web Form UI is created as a ASP.NET Web Application (Web project). The code that performs business logic should be extracted out into a common library (Lib project).

Utility Classes

The Automator class used in my previous article used reflection to auto-populate the form controls. Since the automators are specific to the UI being populated, we need to create separate automator modules for Windows and Web forms.

We will create helper classes for getting or setting the value of a property on an object using reflection since this code will be shared by the above Automators. Two classes are used for this purpose viz. ReflectHelper and PropertyHelper.

The PropertyHelper extends the Reflection technique to be used with nested properties e.g. Let us consider the case where the Registration class is associated with an Address. The code snippet below highlights some of the interfaces and their corresponding implementations (Value Objects) which are used to store the state of the UI.

Let us assume that the instance of Registration class is assigned to a variable reg. The controls on the UI can be mapped to properties on the reg by using the naming convention as shown below. Nested properties are separated by an underscore "_" character as using a period "." for naming a UI control is disallowed.

Notice the striking similarity in code for the above two cases. The programmer can now write consistent code for either of the two presentation libraries; Thanks to the common library and multi-tiered strategy approach.

Services Tier

The question to be asked here is "What are the services that the application needs to deliver?" The following code snippet will define the interfaces for the services to be provided by the application.

The services to be provided are implemented by a class or group of classes in the Business tier which in our example is Lib.AccountManager. The Presentation tier will communicate with the application through the Services tier by using the services defined here.

Business Tier

This tier comprises of classes that perform business validation and execute transactions. They communicate with the classes in the Integration tier if necessary to execute business logic and persist data captured by the UI.

Integration Tier

The classes that access back-end resources such as a RDBMS database constitute the formation of this tier. This example provides stubs as shown in the code snippet below to simulate the actual behavior by using an in-memory Hashtable as a replacement to the actual database. These classes communicate with the Resource tier to persist or retrieve data.

Resource Tier

Any resource which can persist data such as a RDBMS database or data store e.g. Microsoft SQL Server or Oracle constitutes in the making of this tier. Data stored in this tier is used by the Business tier via the Integration tier to perform the necessary business logic.

Summary

Services Tier - Services namespace consisting of interfaces for Value Objects in the Business tier and services provided by the application.

Business Tier - Lib namespace consisting of AccountManager which provides implementation for the services mentioned above in the Service tier and Value Objects such as Account, Registration etc. which encapsulate the UI state.

Integration Tier - Dao namespace consisting of Data Access Objects which communicate with the Resource tier. Stubs of such classes are provided.

Resource Tier - Any data source such as Microsoft SQL Server. Not used in this article to avoid complexity.

Create a Visual Studio.NET Solution and add the above projects to the solution.

Project Name

Dependencies

Utility

Lib

Utility

Win

Lib, Utility

Web

Lib, Utility

Create a virtual directory Web for running the ASP.NET Web Application. Type http://localhost/Web/WebForm.aspx in the browser Address Bar to launch the web application. Windows application can be started from the Win.exe file found in the Win\bin\Release directory. Use the steps mentioned below to test the application (ASP.NET Web or Windows).

Click on Register button without filling in any information - Validation error for required fields.

Fill in all the required information and click on the Register button - Registration successful.

Fill in the same information as above without ending the session and click on the Register button - Validation Error for duplicate account.

Possible Future Enhancements

The ErrorProvider for ASP.NET Web Forms can be re-written as a custom control (Inheriting from System.Web.UI.Control) similar to the one for Windows Forms providing consistent behavior in both the presentation environments.

Reflection can be used to populate objects in the Integration tier by mapping the property names (including nested properties) to the column names on the database tables. The common functionality in the Resource tier can be extracted out into a reusable framework library.

The ValidationHelper can be replaced by a validation framework which can be reusable across application boundaries.

Auto-population of UI forms can also be accomplished using custom attributes as suggested by Sébastien Lorion in response to my previous article.

An ASP.NET Web Service can provide the application functionality through a Windows or Web client similar to the one that we have developed.

References/Links

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

The problem lies in the creation of the WebAutomator. A different instance of WebForm is created every time the page is posted back. So the webform instance stored in the automator (as an argument to the constructor) is not the same instance of the form you are trying to restore data on.

The form is now correctly restored. One way to solve this is to provide a set method for WebForm property and use it to set the property value to 'this' before restore e.g.private void Restore_Click(object sender, System.EventArgs e){ this.automator.WebForm = this; this.automator.Restore();}

I must confess that the code submitted with this article is in fact not up-to-the-mark from what would be acceptable industry standards. The documentation for the code should follow the design-by-contract principle.

I usually make it a point to see that the documentation is up to date and the code reflects on what the contract of the class or method advertises. Always adopt industry coding standards and be consistent.

I would suggest that you always document your code to the extent that if you were to look at the code after a substantial time duration (say a couple of years), you should be able to be productive in the least amount of time. Read and understand technical articles, Practice and Practice!

The address interface is not necessary but can be used to provide immutable behavior to your clients. The properties on the interface can be readonly so the client can only extract the address information but cannot change it if a situation demands such a behavior.

In the case of your Service layer you expose interfaces which are finer-grained compared to the business classes ... In fact the Services layer should be coarser-grained imho, and the business layer - finer-graned, don't you think so? I can expose a certain API to external clients, but behind I may have hundreds of business objects coordinating in order to fulfill 1 API request. In your example the AccountManager even implements 2 services ... What do you think about this?

I have exposed the services as interfaces to declare what the application promises to deliver. The business classes needed to implement that service could run into hundreds if need be. The interfaces promises a consistent API for clients to use while how the service is implemented is up to the business tier.

There could be a Facade layer (as you rightly point out which aggregates some of the business logic) between the service and business layers. Selection of the n-tiers is a matter of taste and I would leave that to the designer as efficiency vs. flexibility often becomes a issue in reality.

Some of the other interfaces in the services tier correspond to the value objects in business tier with read-only properties.

I have fixed a bug in the Windows Form code where the value of the Country field by default (It works if you change the selection) was not propagated to the business tier. The source code provided does have the fix. Please recompile to update the executable.