ER Diagrams, Domain Model, and N-Layer Architecture with ASP.NET 3.5 (part2)

Build robust, scalable ASP.NET applications quickly and easily.

1-tier 3-layer Architecture using a Domain Model

Based on the class diagram in the first part, we will create a new simple 3-layered application using the entities defined in the above domain model. We will create a new ASP.NET Web Project in VS. This time, you should create two new folders inside your root web folder (using the Add New Folder option in VS):

  • BL: This folder will contain all of the business logic domain classes
  • DAL: This folder will contain the data access code files (for each entity)

Layer 1: Data Access Layer (DAL)

First, we will create a DAL class for each entity. We will name each DAL class using this naming pattern: EntityDAL. Let us see the CustomerDAL class:

using DomainModel.BL;
namespace DomainModel.DAL
{
public class CustomerDAL
{
public static void AddCustomer(Customer cs)
{
using (SqlConnection con =
new SqlConnection(SQLHelper.GetConnectionString()))
{
SqlParameter[] par = new SqlParameter[4];
par[0] = new SqlParameter("@customerID", cs.ID);
par[0].Direction = ParameterDirection.Output;
par[1] = new SqlParameter("@name", cs.Name);
par[2] = new SqlParameter("@address", cs.Address);
par[3] = new SqlParameter(
"@phoneNo", cs.PhoneNumber);
int rowNo = SQLHelper.ExecuteNonQuery(
con, CommandType.StoredProcedure,
"OMS_AddCustomer", par);
cs.ID = Convert.ToInt32(par[0].Value);
}
}
public static void DeleteCustomer(int customerID)
{
using (SqlConnection con =
new SqlConnection(SQLHelper.GetConnectionString()))
{
SqlParameter[] par = new SqlParameter[1];
par[0] = new SqlParameter("@customerID", customerID);
int rowNo = SQLHelper.ExecuteNonQuery(
con, CommandType.StoredProcedure,
"OMS_DeleteCustomer", par);
}
}
public static void UpdateCustomer(Customer cs)
{
using (SqlConnection con = new
SqlConnection(SQLHelper.GetConnectionString()))
{
SqlParameter[] par = new SqlParameter[4];
par[0] = new SqlParameter("@customerID", cs.ID);
par[1] = new SqlParameter("@address", cs.Address);
par[2] = new SqlParameter("@name", cs.Name);
par[3] = new SqlParameter(
"@phoneNo", cs.PhoneNumber);
int rowNo = SQLHelper.ExecuteNonQuery(
con, CommandType.StoredProcedure,
"OMS_UpdateCustomer", par);
}
}
public static void GetCustomer(Customer cs)
{
using (SqlConnection con =
new SqlConnection(SQLHelper.GetConnectionString()))
{
SqlParameter[] par = new SqlParameter[1];
par[0] = new SqlParameter("@customerID", customerID);
using (SqlDataReader dr =
SQLHelper.ExecuteReader(con,
CommandType.StoredProcedure,
"OMS_GetCustomer", par))
{
c = new Customer();
while (dr.Read())
{
c.Name =
SQLHelper.CheckStringNull(dr["Name"]);
c.PhoneNumber =
SQLHelper.CheckStringNull(dr["PhoneNo"]);
c.Address =
SQLHelper.CheckStringNull(dr["Address"]);
c.ID = SQLHelper.CheckIntNull(dr["ID"]);
}
}
}
}
public static List<Customer> GetAllCustomers()
{
List<Customer> cuList = new List<Customer>();
using (SqlConnection con =
new SqlConnection(SQLHelper.GetConnectionString()))
{
using (SqlDataReader dr =
SQLHelper.ExecuteReader(con,CommandType.
StoredProcedure,"OMS_GetAllCustomer"))
{
while (dr.Read())
{
Customer customer = new Customer();
customer.Name =
SQLHelper.CheckStringNull(dr["Name"]);
customer.PhoneNumber =
SQLHelper.CheckStringNull(dr["PhoneNo"]);
customer.Address =
SQLHelper.CheckStringNull(dr["Address"]);
customer.ID =
SQLHelper.CheckIntNull(dr["ID"]);
cuList.Add(customer);
}
}
}
return cuList;
}
}//end class
}

Here, we have used the SqlHelper class, which contains generic data access utility methods, so that we can avoid code repletion.

Layer 2: Business Layer (BL)

Next, we will create classes for each of the domain entities. We will put all of these classes under the new BL folder with this namespace: DomainModel.BL. Create a new C# class file named Customer.cs under the BL folder. Here is the first Customer class:

using DomainModel.DAL;
namespace DomainModel.BL
{
public class Customer
{
private int _ID;
private string _name;
private string _address;
private string _phoneNumber;
private List<Customer> _customerCollection;
public int ID
{
get { return _ID; }
set { _ID = value; }
}
public string Name
{
get { return _name; }
set { _name = value; }
}
public string Address
{
get { return _address; }
set { _address = value; }
}
public string PhoneNumber
{
get { return _phoneNumber; }
set { _phoneNumber = value; }
}
public List<Customer> CustomerCollection
{
get { return _customerCollection; }
set { _customerCollection = value; }
}
public void Add()
{
CustomerDAL.AddCustomer(this);
}
public void Delete(int customerID)
{
CustomerDAL.DeleteCustomer(this.ID);
}
public void Update()
{
CustomerDAL.UpdateCustomer(this);
}
public void Load()
{
CustomerDAL.GetCustomer(this.ID);
}
public void GetAll()
{
this.CustomerCollection = CustomerDAL.GetAllCustomers();
}
}//end class
}//end namespace

The CustomerDAL class is pretty simple: we are fetching the data from the database using data readers, and performing all data related operations using the Customer business object. This Customer class is defined in the Customer.cs class we created earlier. This BL class is calling DAL methods, so it needs a reference to the DAL namespace (using DomainModel.DAL). Similarly, the DAL class we created earlier used Customer business objects. That's why it also needed the BL namespace.

We are using generics to create a collection of Customer objects. The BL communicates with DAL to get the data and perform updates. Now, we will see how the UI (which is under a different namespace) talks to BL without even knowing about DAL.

Layer 3: The UI Layer

Here is the code in the AllCustomers.aspx.cs page that shows a list of all of the customers from the DB (there is a data list on the web form, which will show a list of the customers):

using DomainModel.BL;
namespace DomainModel.UI
{
//page load
private void FillAllCustomers()
{
Customer c = new Customer();
c.GetAll();
List<Customer> cuList = c.CustomerCollection;
dtlstAllCustomer.DataSource = cuList;
dtlstAllCustomer.DataBind();
}
}

So in the UI class, we neither have any data access code nor are we calling data access class methods from this layer (as was the case with the 1-tier 2-layer style we saw earlier in this article). We have a reference to the BL layer (using DomainModel.BL), and we are using the Customer business object to return a generic list of customer objects, which we are binding to the data list control (showing a list of all the customers). So the GUI layer does not know anything about the DAL layer, and is completely independent of it.

The idea here is to understand how a 3-Layer architecture can provide more flexibility and loose-coupling to your project. In the next section, we will learn how we can use object data source controls to implement a 3-layer architecture without writing much code ourselves.

Object Data Source Controls    

Data source controls can replace the data access code but they tightly couple the GUI to the data methods. To overcome this problem, Microsoft introduced object data source controls, so that we can bind directly to business objects, making it possible to use them in a 3-tier architecture.

Let's see how using object data source controls will shape our application:

  1. Create a new web project using VS.
  2. Add a new form named datasource-customer.aspx.
  3. Add an object data source control, as shown here (drag and drop the object data source control from the Data tab under ToolBox in VS):
  4. Now, we need to configure this object data source control. We first need to set the Business object , where we select our customer class:
  5. Then, we need to set the SELECT, UPDATE, and INSERT methods. For our sample, we will just set the SELECT method:
  6. Then, we select Finish. We then add a GridView control on the same page and set the data source to our object data source control:
  7. Now we run the page, and voila! We see all of the records without using any code in the UI layer!

    ER Diagrams, Domain Model, and N-Layer Architecture with ASP.NET 3.5 (part2)

As we can see, using object data source controls complements the domain model and helps us avoid writing the UI layer code, as we can directly bind custom entities to data-bound controls in UI.

However, there are a few issues in using object data source controls:

  • They are not very flexible. Sometimes we need to display data in UI in a complex way (which can be user friendly, but code un-friendly). In such cases, it is best to use and manipulate custom collections using manual coding; you cannot even extend the control to customize it.
  • There is a slight performance hit when using object data source controls instead of using manual coding. This hit comes through the use of reflection by the control to access a class's attributes and methods.

Reflection is a technique which VS uses to get metadata information about other entities, such as a class file or an assembly. Using reflection, the object data source control will first "read" the class to get all of the attributes and then use this metadata to connect to and perform operations on the class. On account of this additional "reading" step, the application suffers a performance hit.

Therefore, for a flexible approach, it is best to use custom code. But for small projects where we don't foresee any major complexity and performance issues, object data source controls are a good option to save on development time while supporting a flexible n-layer option.

Summary

All of the samples we covered in this two-part 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.

We then focused on a 3-layered application structure for OMS, and looked at how both custom code and object data source controls can be used in this architecture.

If you have read this article you may be interested to view :

Books to Consider

Microsoft AJAX Library Essentials: Client-side ASP.NET AJAX 1.0 Explained
$ 12.00
ASP.NET 3.5 Application Architecture and Design
$ 14.40
comments powered by Disqus
X

An Introduction to 3D Printing

Explore the future of manufacturing and design  - read our guide to 3d printing for free