Let us start with a 1-tier ASP.NET application configuration.
Note that the application as a whole including database and client browser is three tier.
We can call this 1-tier architecture a 3-tier architecture if we include the browser and database (if used). For the rest of this article we will ignore the database and browser as separate tiers so that we can focus on how to divide the main ASP.NET application layers logically, using the n-layer pattern to its best use.
We will first try to separate the data access and logical code into their own separate layers and see how we can introduce flexibility and re-usability into our solution. We will understand this with a sample project. Before we go ahead into the technical details and code, we will first learn about two important terms: ER Diagram and Domain Model, and how they help us in getting a good understanding of the application we need to develop.
Entity-Relationship diagrams, or ER diagrams in short, are graphical representations depicting relationships between different entities in a system. We humans understand and remember pictures or images more easily than textual information. When we first start to understand a project we need to see how different entities in the project relate to each other. ER diagrams help us achieve that goal by graphically describing the relationships.
An entity can be thought of as an object in a system that can be identified uniquely. An entity can have attributes; an attribute is simply a property we can associate with an entity. For example, a Car entity can have the following attributes: EngineCapacity, NumberofGears, SeatingCapacity, Mileage, and so on. So attributes are basically fields holding data to indentify an entity. Attributes cannot exist without an entity.
Let us understand ER diagrams in detail with a simple e-commerce example: a very basic Order Management System. We will be building a simple web based system to track customer's orders, and manage customers and products.
To start with, let us list the basic entities for our simplified Order Management System (OMS):
- Customer: A person who can place Orders to buy Products.
- Order: An order placed by a Customer. There can be multiple Products bought by a Customer in one Order.
- Product: A Product is an object that can be purchased by a Customer.
- Category: Category of a Product. A Category can have multiple Products, and a Product can belong to many Categories. For example, a mixer-grinder can be under the Electronic Gadgets category as well as in Home Appliances.
- OrderLineItem: An Order can be for multiple Products. Each individual Product in an order will be encapsulated by an OrderLineItem. So an Order can have multiple OrderLineItems.
Now, let us picture the relationship between the core business entities is defined using an Entity-Relationship diagram. Our ER diagram will show the relational associations between the entities from a database's perspective. So it is more of a relational model and will not show any of the object-oriented associations (for which we will use the Domain Model in the later sections of this article). In an ER diagram, we show entities using rectangular boxes, the relationships between entities using diamond boxes and attributes using oval boxes, as shown below:
The purpose of using such shapes is to make the ER diagram clear and concise, depicting the relational model as closely as possible without using long sentences or text. So the Customer entity with some of the basic attributes can be depicted in an ER diagram as follows:
Now, let us create an ER diagram for our Order Management System. For the sake of simplicity, we will not list the attributes of the entities involved.
Here is how the ER diagram looks:
The above ER diagram depicts the relationships between the OMS entities but is still incomplete as the relationships do not show how the entities are quantitatively related to each other. We will now look at how to quantify relationships using degree and cardinality.
Degree and Cardinality of a Relationship
The relationships in an ER diagram can also have a degree. A degree specifies the multiplicity of a relationship. In simpler terms, it refers to the number of entities involved in a relationship. All relationships in an OMS ER diagram have a degree of two, also called binary relationships. For example, in Customer-Order relationships only two entities are involved—Customer and Order; so it's a two degree relationship. Most relationships you come across would be binary.
Another term associated with a relationship is cardinality. The cardinality of a relationship identifies the number of instances of entities involved in that particular relationship. For example, an Order can have multiple OrderLineItems, which means the cardinality of the relationship between Order and OrderLineItem is one-to-many. The three commonly-used cardinalities of a relationship are:
- One-to-one: Depicted as 1:1
Example: One OrderLineItem can have only one Product; so the OrderLineItem and Product entities share a one-to-one relationship
- One-to-many: Depicted as 1:n
Example: One customer can place multiple orders, so the Customer and Order entities share a one-to-many relationship
- Many-to-many: Depicted as n:m
Example: One Product can be included in multiple Categories and one Category can contain multiple Products; therefore the Product and Category entities share a many-to-many relationship
After adding the cardinality of the relationships to our ER diagram, here is how it will look:
This basic ER diagrams tells us a lot about how the different entities in the system are related to each other, and can help new programmers to quickly understand the logic and the relationships of the system they are working on. Each entity will be a unique table in the database.
OMS Project using 2-Layer
We know that the default coding style in ASP.NET 2.0 already supports the 1-tier 1-layer style, with two sub-layers in the main UI layer as follows:
- Designer code files: ASPX markup files
- Code behind files: Files containing C# or VB.NET code
Because both of these layers contain the UI code, we can include them as a part of the UI layer. These two layers help us to separate the markup and the code from each other. However, it is still not advisable to have logical code, such as data access or business logic, directly in these code-behind files.
Now, one way to create an ASP.NET web application for our Order Management System (OMS) in just one layer is by using a DataSet (or DataReader) to fill the front-end UI elements directly in the code-behind classes. This will involve writing data access code in the UI layer (code-behind), and will tightly bind this UI layer with the data access logic, making the application rigid (inflexible), harder to maintain, and less scalable.
In order to have greater flexibility, and to keep the UI layer completely independent of the data access and business logic code, we need to put these elements in separate files. So we will now try and introduce some loose-coupling by following a 2-layer approach this time. What we will do is, write all data access code in separate class files instead of using the code-behind files of the UI layer. This will make the UI layer independent of the data-access code.
We are assuming that we do not have any specific business logic code at this point, or else we would have put that under another layer with its own namespace, making it a 3-layered architecture. We will examine this in the upcoming sections of this article.
Let us see how we can move from this 1-tier 1-layer style to a 1-tier 2-layer style. Using the ER diagram above as reference, we can create a 2-Layer architecture for our OMS with these layers:
- UI-layer with ASPX and code-behind classes
- Data access classes under a different namespace but in the same project
So let's start with a new VS 2008 project. We will create a new ASP.NET Web Project in C#, and add a new web form, ProductList.aspx, which will simply display a list of all the products using a Repeater control. The purpose of this project is to show how we can logically break up the UI layer further by separating the data access code into another class file.
The following is the ASPX markup of the ProductList page (unnecessary elements and tags have been removed to keep things simple):
<asp:Repeater ID="prodRepeater" runat="server">
Product Code: <%# Eval("Code")%>
Name: <%# Eval("Name")%>
Unit Price: $<%# Eval("UnitPrice")%>
In this ASPX file, we only have a Repeater control, which we will bind with the data in the code-behind file.
Here is the code in the ProductList.aspx.cs code-behind file:
public partial class _Default : System.Web.UI.Page
/// Page Load method
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Page_Load(object sender, EventArgs e)
DataTable dt = DAL.GetAllProducts();
prodRepeater.DataSource = dt;
Note that we don't have any data access code in the code-behind sample above. We are just calling the GetAllProducts() method, which has all of data access code wrapped in a different class named DAL. We can logically separate out the code, by using different namespaces to achieve code re-use and greater architectural flexibility. So we created a new class named DAL under a different namespace from the UI layer code files. Here is the DAL code:
public class DAL
/// Load all comments from the Access DB
public static DataTable GetAllProducts()
string sCon = ConfigurationManager.ConnectionStrings.ConnectionString;
using (SqlConnection cn = new SqlConnection(sCon))
string sQuery = @"SELECT * FROM OMS_Product";
SqlCommand cmd = new SqlCommand(sQuery, cn);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
So we have separated the data access code in a new logical layer, using a separate namespace, OMS.Code, and using a new class. Now, if we want to, we can re-use the same code in the other pages as well. Furthermore, methods to add and edit a product can be defined in this class and then used in the UI layer. This allows multiple developers to work on the DAL and UI layers simultaneously.
Even though we have a logical separation of the code in this 2-layer sample architecture, we are still not using real Object Oriented Programming (OOP). All of the Object-Oriented Programming we have used so far has been the default structure the .NET framework has provided, such as the Page class, and so on.
When a project grows big in size as well as complexity, using the 2-layer model discussed above can become cumbersome and cause scalability and flexibility issues. If the project grows in complexity, then we will be putting all of the business logic code in either the DAL or the UI layer. This business logic code includes business rules. For example, if the customer orders a certain number of products in one order, he gets a certain level of discount. If we code such business rules in the UI layer, then if the rules change we need to change the UI as well, which is not ideal, especially in cases where we can have multiple UIs for the same code, for example one normal web browser UI and another mobile-based UI.
We also cannot put business logic code in the DAL layer because the DAL layer should only contain data access code which should not be mixed with any kind of business processing logic. In fact the DAL layer should be quite "dumb"–there should be no "logic" inside it because it is mostly a utility layer which only needs to put data in and pull data out from a data store.
To make our applications more scalable and to reap the benefit of OOP, we need to create objects, and wrap business behavior in their methods. This is where the Domain Model comes into the picture.
Domain Model using UML
The domain model is a more object-oriented way of indicating the relationships between different objects in the context of the business logic of the application. It is similar to the ER diagram. But instead of merely showing the relationships between the entities involved, it graphically reflects how these entities relate to each other in an object-oriented fashion. On the other hand, an ER diagram is only focused from a relational perspective.
Unified Modeling Language, or UML in short, is a graphical language used to describe object-oriented designs for software systems. UML is quite a vast language, but we will focus more on class diagrams and UML relationships to represent our domain model. Class diagrams are widely used in every object-oriented system to describe the different types of internal relationships between the different business entities.
Before going for a 3-layer object-oriented system, we need to create a domain model of the system. So we need to put all of the business code into separate logical structures and start creating a domain model, in order to understand the different business entities involved.
For this, we need to "organize" the code by breaking it down into logical entities, which we call objects, and create relationships between them. The resulting set of objects with relationships defined between them would be known as the domain model of the application. It is so called because this model illustrates how different entities in the application domain would interact with each other.
We use the following shapes in our class diagram:
We will learn in detail what each figure represents, and how to create a domain model using them.
A class diagram simply represents how different entities are related to each other in an object-oriented system. Class diagrams are different from ER diagrams because class diagrams deal with relationships in an object-oriented manner, showing inheritance, interfaces and so on, whereas an ER diagram can only depict relational models (for Relational Database Management Systems, or RDBMSs).
In order to create a class diagram for our OMS, let us highlight the major entities in our OMS in terms of domain classes:
The rectangular boxes denote the entities (or classes) with the class name in the header and the attributes (or fields) below it. The arrows define relationships between entities. These relationships can be of different types and are depicted differently using different arrow styles.
Broadly speaking, we can place class relationships into these categories:
- Dependency relationship
Let's explore each of these UML relationships in detail.
In an ER diagram for two entities A and B, we can show only one type of relationship–a Relational relationship–which means that entity A is somehow related to entity B. But in a class diagram, the relationships can be further divided on the basis of object-oriented principles such as inheritance, association, and so on. The following sections describe the main UML relationships used in a class diagram.
A Dependency exists between two elements if changes to one element will affect the other. A dependency relationship is the simplest relationship of all, and means that Entity 1 depends on Entity 2 in such a way that any change in entity 2 might break entity 1. This is a one-way relationship only—changes in entity 1 will not affect entity 2 in any manner. Dependency relationships are represented by a broken (dashed) line with an "empty" arrow (--->). The direction of this arrow flows to the entity that is dependent on the entity that the arrow flows from.
A simple example would be:
public class Entity1
public void MethodX (Entity2 en)
// . . .
public void MethodY ()
Entity2 en2 = new Entity2();
// . . .
In the above pseudo code, Entity2 is used in Entity1 first as a method parameter and secondly inside MethodY() as a local variable. Both of these cases show a dependency relationship.
An important point about dependency relationships relates to the state of the objects involved. The state of Entity2 is not related to the state of Entity-1, as Entity2 is not a member of the Entity1 class. It is only used in the methods as local variable.
An Association shows the relationship between instances of classes. An association is similar to a dependency except that it specifies the relationship in a stricter form. An association means that instead of Entity2 being used in Entity1 as a local variable, it would be a global variable instead, which can be a private, public, or protected class member. In its basic form, it is represented by a solid arrow (instead of dashed as in a dependency relationship).
public class Order //entity1
private Customer _customer;
public Customer GetCustomer ()
In the above pseudo code, the Customer object is a part of the Order class—a private member in this case. This means that the Customer object forms a part of the state of the Order. If you have an Order object, you can easily identify the Customer associated with it. This is not possible in a dependency. Hence, the association is a stronger form of dependency.
An Association relationship can be divided further into two separate relationships, based on the state of the aggregated object in the dependent class.
An Aggregation relationship depicts a classifier as a part of, or as subordinate to, another classifier. For example, if Entity1 goes out of scope, it does not mean that Entity2 has to go out of scope too. That is, the lifetime of Entity2 is not necessarily controlled by Entity1. An aggregation is represented by a straight arrow, with an empty diamond at the tail, as shown in the following figure:
So, in our example, Entity2 is a part of (or subordinate to) Entity 1. If you destroy the parent class (Entity 1) in an aggregation (weak) relationship, the child class (Entity 2) can survive on its own.
Let's understand aggregations by using our example of the Order Management System. Consider the OrderLine and Product classes. An OrderLine can have multiple quantities of one Product. If an OrderLine is destroyed, it does not mean that we delete the Product as well. A Product can exist independently of the OrderLine object. Here is the relationship diagram between OrderLine and Product classes:
In the diagram, we can see an Aggregation relationship between OrderLine and Product classes. Put simply, the above diagram states that if an order is cancelled, all of the products will not be destroyed; they will only be "de-associated" from that particular order.
A Composition is exactly like Aggregation except that the lifetime of the 'part' is controlled by the 'whole'. For example: You have a 'student' who has a 'schedule'. If you destroy the student, the schedule will cease to exist.
In this case, the associated entity is destroyed when the parent entity goes out of scope. Composition is represented by a straight arrow with a solid diamond at the tail, as shown below.
In our case, Entity-2 is controlled by Entity-1. If Entity 1 is destroyed in a composition (strong) relationship, Entity-2 is destroyed as well.
Let's understand compositions by using our example of the Order Management System. Consider the Customer and Order classes. A Customer can have one or more orders, and an Order can have one or more Products (in order lines). An Order object cannot exist on its own without a Customer. So the following Composition indicates that if a Customer object goes out of scope, the Orders associated with that Customer go out of scope too.
Inheritance is a very widely known and common feature of OOP. In UML, inheritance is depicted using generalization relationships, depicted by a straight arrow with a hollow arrowhead (triangle) at one end. A generalization relationship (also known as a "is-a" relationship) implies that a specialized (child) class is based on a general (parent) class.
Here is a diagram illustrating this:
Here, we can see that the arrow points in the direction of the base class. In our Order Management System, we can have a base class for all customers; we can call it Person class so that we have other classes derived from it, such as Customer, CSR (Customer Sales Representative), and so on.
Realization is similar to generalization but depicts the relationship between an interface and a class implementing that interface. In UML, realization is depicted with a dashed arrow with a hollow arrowhead (triangle) at one end. A realization relationship exists between the two classes when one of them must realize, or implement, the behavior specified by the other.
For example, a realization relationship connects an interface to an implementing class. The interface specifies the behaviors, and the implementing class implements the behaviors. Here is a diagram illustrating this:
Here, we can see that the arrow points in the direction of the interface. Note that the italicized text in entities that are interfaces. It is UML convention to italicize interfaces.
Multiplicity quantifies the relationship between two entities. Multiplicity is closely related to the cardinality of a relationship, which we learned about earlier when discussing ER diagram. Multiplicity indicates how many instances of classes (objects) are related to each other in a UML relationship. The following is a list of different multiplicities we can have between two entities in a class diagram:
- One-to-one: For example, one OrderLine object can have only one product. This is depicted as follows:
Note how we show a 1:1 multiplicity using the number "1" at the end points of the aggregation relationship.
- One-to-many: For example, a customer can have many orders. This is depicted as follows:
Note the text "1" and "*" near the entities; these are multiplicity indicators. In the above example, the multiplicity indicates that one (1) customer can have multiple orders (*). We depict "many" using a "*" (asterisk) symbol.
The relationship between Order and OrderLine objects is the same. An order can have multiple products; each product will be shown in a separate line (called as OrderLine) in the Order. So there can be one or more order lines for a single order, as shown here:
The above diagram confirms that for each order, there will be one or more order lines. We can't use 0..* here in place of 1..* because each order will have atleast one product in it (as one order line item).
Also, if an order gets cancelled (destroyed), then all order lines will be destroyed. It doesn't make sense to have order lines that are not a part of any order—hence the composition.
- Many-to-many: A Product can belong to multiple Categories, and a Category object can include multiple Product objects. To depict such many-to-many relationships, we use asterisk at both ends of the relationship arrow, as shown here:
Also note the aggregation relationship between the Product and the Category, because both can exist independently of each other.
So, now, we can combine all of the above diagrams and create a simple class diagram with all of the relationships and multiplicities for our OMS. Here is the combined UML class diagram for our sample application:
So we have a very simple domain model of a simple Order Management System. Now, based on the above classes, let's look at how we can convert this domain model to code by creating a 1-tier 3-layer architecture based web application.
All of the samples we covered in this article were of the 1-tier n-layer style. We learned how to create a 1-tier 2 layer architecture using logical code separation. Then we focused on the need for a 3-layered solution and examined ER-diagrams, domain models and UML, all of which are important tools that aid in the understanding of commercial projects required to build a 3-layered structure.
In the second part of the article we will explore a 1-tier 3-layer Architecture using a Domain Model and Object Data Source Controls.
If you have read this article you may be interested to view :