Breaking News

Editors Picks

Wednesday, July 7, 2010

3-Tier Architecture in ASP.NET with C#


What is a 3-tier architecture?

Three-tier (layer) is a client-server architecture in which the user interface, business process (business rules) and data storage and data access are developed and maintained as independent modules or most often on separate platforms. Basically, there are 3 layers, tier 1 (presentation tier, GUI tier), tier 2 (business objects, business logic tier) and tier 3 (data access tier). These tiers can be developed and tested separately.
What is the need for dividing the code in 3-tiers? Separation of the user interface from business logic and database access has many advantages. Some of the advantages are as follows:
  • Reusability of the business logic component results in quick development. Let's say we have a module that handles adding, updating, deleting and finding customers in the system. As this component is developed and tested, we can use it in any other project that might involve maintaining customers.
  • Transformation of the system is easy. Since the business logic is separate from the data access layer, changing the data access layer won�t affect the business logic module much. Let's say if we are moving from SQL Server data storage to Oracle there shouldn�t be any changes required in the business layer component and in the GUI component.
  • Change management of the system is easy. Let's say if there is a minor change in the business logic, we don�t have to install the entire system in individual user�s PCs. E.g. if GST (TAX) is changed from 10% to 15% we only need to update the business logic component without affecting the users and without any downtime.
  • Having separate functionality servers allows for parallel development of individual tiers by application specialists.
  • Provides more flexible resource allocation. Can reduce the network traffic by having the functionality servers strip data to the precise structure needed before sending it to the clients.





Introduction 

3-Tier architecture generally contains UI or Presentation Layer, Business Access Layer (BAL) or Business Logic Layer and Data Access Layer (DAL). 

Presentation Layer (UI) 
Presentation layer cotains pages like .aspx or windows form where data is presented to the user or input is taken from the user. 

Business Access Layer (BAL) or Business Logic Layer 
BAL contains business logic, validations or calculations related with the data, if needed. I will call it Business Access Layer in my demo. 

Data Access Layer (DAL) 
DAL contains methods that helps business layer to connect the data and perform required action, might be returning data or manipulating data (insert, update, delete etc). For this demo application, I have taken a very simple example. I am assuming that I have to play with record of persons (FirstName, LastName, Age) and I will refer only these data through out this article.



A 3-tier application is a program which is organized into three major disjunctive tiers. These tiers are
  • Presentation Tier  (Front end)
  • Logical Tier  (Middleware)
  • Data Tier (Backend).
Each layer can be deployed in geographically separated computers in a network. Some architects divide Logic Tier in to two sub tiers  Business  and Data Access Tiers,  in order to  increase scalability and transparency. The tiers can be deployed on physically separated machines. The characteristic of the tier communication is that the tiers will communicate only to their adjacent neighbors. For an example, The Presentation Tier will interact directly with the Business Tier and not directly with Data Access or Data Tiers.
   



1.1  Data Tier
This Tier is responsible for retrieving, storing and updating from Information therefore this tier can be ideally represented through a commercial database. We consider stored procedures as a part of te Data Tier. Usage of stored procedures increases the performance and code transparency of an application 
1.2  Logical Tier
This is the brain of the 3.Tier Application. Some architects do not make any distinction between Business Tier and Data Access Tier. Their main argumentation is that additional tiers will screw down performance. I think that we will have more advantages, if we separate Logical Tier in to Business Tier and Data Access Tier. Some of these advantages are
  • Increases code transparency
  • Supports changes in Data Layer. You can change or alter database with out touching the Business Layer and this would be a very minimum touch up.  
1.2.1  Business Tier
This sub tier contents classes to calculate aggregated values such like total revenue, cash flow and ebit and this tier doesnt know about any GUI controls and how to access databases. The classes of Data Access Tier will supply the needy information from the databases to this sub tier.
1.2.2  Data Access Tier:
This tier acts as an interface to Data Tier. This tier knows, how to (from which database) retrieve and store information. 
1.3  Presentation Tier:
This Tier is responsible for communication with the users and web service consumers and it will use objects from Business Layer to response GUI raised events.
After this brief theory, I think we should move now to the practical part. Our aim is to develop a work diary for employees, in which they can record daily project activities.


Presentation Layer






User Interface tier

This is a chunk of code from the user interface. I am only including the functions that are used to call the middle tier or the business logic layer.
I am keeping a reference to business logic layer as BOCustomer.
//This function get the details from the user via GUI 

//tier and calls the Add method of business logic layer.

private void cmdAdd_Click(object sender, System.EventArgs e)
{
      try
      {
            cus = new BOCustomer();
            cus.cusID=txtID.Text.ToString();
            cus.LName = txtLName.Text.ToString();
            cus.FName = txtFName.Text.ToString();
            cus.Tel= txtTel.Text.ToString();
            cus.Address = txtAddress.Text.ToString();
            cus.Add();
      }
      catch(Exception err)
      {
            MessageBox.Show(err.Message.ToString());
      }
}

//This function gets the ID from the user and finds the 

//customer details and return the details in the form of

//a dataset via busniss object layer. Then it loops through 

//the content of the dataset and fills the controls.

 
private void cmdFind_Click(object sender, System.EventArgs e)
{
      try
      {
            String cusID = txtID.Text.ToString();
                  
            BOCustomer thisCus = new BOCustomer();
                  
            DataSet ds = thisCus.Find(cusID);
 
            DataRow row;
            row = ds.Tables[0].Rows[0];
 
            //via looping

            foreach(DataRow rows in ds.Tables[0].Rows )
            {
               txtFName.Text = rows["CUS_F_NAME"].ToString();
               txtLName.Text = rows["CUS_L_NAME"].ToString();
               txtAddress.Text = rows["CUS_ADDRESS"].ToString();
               txtTel.Text = rows["CUS_TEL"].ToString();
            }
      }
      catch (Exception err)
      {
            MessageBox.Show(err.Message.ToString());
      }
 
}

//this function used to update the customer details. 

private void cmdUpdate_Click(object sender, 
                                 System.EventArgs e)
{
      try
      {
            cus = new BOCustomer();
            cus.cusID=txtID.Text.ToString();
            cus.LName = txtLName.Text.ToString();
            cus.FName = txtFName.Text.ToString();
            cus.Tel= txtTel.Text.ToString();
            cus.Address = txtAddress.Text.ToString();
 
            cus.Update();
      }
      catch(Exception err)
      {
            MessageBox.Show(err.Message.ToString());
      }
}


Business Access Layer (BAL)

Now, create a class named PersonBAL3 into App_Code folder by right clicking it and write respective methods for calling Insert, Delete, Update and Load methods of Data Access Layer class file (PersonDAL3) (In my case I have a 3-Tier folder inside App_Code folder, you can directly add inside App_Code or you can create a separate project for BAL and add reference of this project into your Presentation Layer). As we don't have any business logic here so simply instantiate the PersonDAL3 class of DAL and call methods. Below is the code for BAL (Your can overwrite your default written code for the class file by pasting this code). 

 using System;
using System.Data;

namespace _3tierarchitecture
{
      /// <SUMMARY>

      /// Summary description for BOCustomer.

      /// </SUMMARY>

      
      public class BOCustomer
      {
            //Customer properties

            private String fName;
            private String lName;
            private String cusId;
            private String address;
            private String tel;
 
            private DACustomer cusData;
 
       public BOCustomer()
       {
            //An instance of the Data access layer!

             cusData = new DACustomer();
         }   
 
 
 
            /// <SUMMARY>

            /// Property FirstName (String)

            /// </SUMMARY>

            public String FName 
            {
      
                  get
                  {
                        return this.fName;
                  }
                  set
                  {
                        try
                        {
                              this.fName = value;
 
                              if (this.fName == "")
                              {
                                    throw new Exception(
                                      "Please provide first name ...");
                              }
                        }
                        catch(Exception e)
                        {
                              throw new Exception(e.Message.ToString());
                        }
                  }
            }
 
            /// <SUMMARY>

            /// Property LastName (String)

            /// </SUMMARY>

            public String LName
            {
                  get
                  {
                        return this.lName;
                  }
                  set
                  {
                        //could be more checkings here eg revmove ' chars

                        //change to proper case

                        //blah blah

                        this.lName = value;
                        if (this.LName == "")
                        {
                              throw new Exception("Please provide name ...");
                        }
 
                  }
            }
             
            /// <SUMMARY>

            /// Property Customer ID (String)

            /// </SUMMARY>

            public String cusID
            {
                  get
                  {
                        return this.cusId;
                  }
                  set
                  {
                        this.cusId = value;
                        if (this.cusID == "")
                        {
                              throw new Exception("Please provide ID ...");
                        }
 
                  }
            }
 
            /// <SUMMARY>

            /// Property Address (String)

            /// </SUMMARY>

            public String Address
            {
                  get
                  {
                        return this.address;
                  }
                  set
                  {
                        this.address = value;
 
                        if (this.Address == "")
                        {
                              throw new Exception("Please provide address ...");
                        }
                  }
            }
 
            /// <SUMMARY>

            /// Property Telephone (String)

            /// </SUMMARY>

            public String Tel
            {
                  get
                  {
                        return this.tel;
                  }
                  set
                  {
                        this.tel = value;
                        if (this.Tel == "")
                        {
                              throw new Exception("Please provide Tel ...");
                        }
 
                  }
            }
 
            /// <SUMMARY>

            /// Function Add new customer. Calls 

            /// the function in Data layer.

            /// </SUMMARY>

            public void Add()
            {
                  cusData.Add(this);
            }
 
 
            /// <SUMMARY>

            /// Function Update customer details. 

            /// Calls the function in Data layer.

            /// </SUMMARY>

            public void Update() 
            {
                  cusData.Update(this);
            }
 
            /// <SUMMARY>

            /// Function Find customer. Calls the 

            /// function in Data layer.

            /// It returns the details of the customer using 

            /// customer ID via a Dataset to GUI tier.

            /// </SUMMARY>

            public DataSet Find(String str) 
            {
                  if (str == "")
                      throw new Exception("Please provide ID to search");
                      
                  DataSet data = null;
 
                  data = cusData.Find(str);
 
                  return data;
            }
      }
}
Data Access Layer 
Lets proceed with desiging 3-Tier architecture. To do that lets proceed with DAL, BAL and then UI. Add a class named by right clicking App_Code folder. (In my case I have a 3-Tier folder inside App_Code folder, you can directly add inside App_Code or you can create a separate project for DAL and add reference of this project into your BAL.) and copy-paste folowing code (Your can overwrite your default written code for the class file by pasting this code).

using System;
using System.Data.OleDb;
using System.Data;

namespace _3tierarchitecture

{

    /// <SUMMARY>

    /// Summary description for DACustomer.

    /// </SUMMARY>

    public class DACustomer
    {
        private OleDbConnection cnn;
        //change connection string as per the 

        //folder you unzip the files

        private const string CnnStr = 
          "Provider=Microsoft.Jet.OLEDB.4.0;Data " +
          "Source= C:\\sunilgurjar_Backup\\Programming\\" + 
             "Csharp\\3tierarchitecture\\customer.mdb;";

        //local variables
        private String strTable="";
        private String strFields="";
        private String strValues="";
        private String insertStr="";
        
        //this needs to be changed based on customer 
        //table fields' Name of the database!
        private const String thisTable = "tblCustomer";
        private const String cus_ID = "CUS_ID";
        private const String cus_LName = "CUS_L_NAME";
        private const String cus_FName = "CUS_F_NAME";
        private const String cus_Tel = "CUS_TEL";
        private const String cus_Address = "CUS_ADDRESS";
 

        public DACustomer()
        {
        }
        
        public DACustomer(BOCustomer cus)
        {
            // A reference of the business object class
        }
        
        //standard dataset function that adds a new customer

        public void Add(BOCustomer cus)
        {

            String str = BuildAddString(cus);
            
            OpenCnn();

            //Open command option - cnn parameter is imporant
            OleDbCommand cmd = new OleDbCommand(str,cnn);


            //execute connection
            cmd.ExecuteNonQuery();
            
            // close connection
            CloseCnn();
            
        }
        
        //standard dataset function that updates 
        //details of a customer based on ID
        public void Update(BOCustomer cus)
        {
            OpenCnn();
            
            String selectStr = "UPDATE " + thisTable + 
                " set " + cus_LName + " = '" + cus.LName + "'" +
                ", " + cus_FName + " = '" + cus.FName + "'" +
                ", " + cus_Address + " = '" + cus.Address + "'" +
                ", " + cus_Tel + " = '" + cus.Tel + "'" +
                " where cus_ID = '" + cus.cusID + "'";

            OleDbCommand cmd = new OleDbCommand(selectStr,cnn);

            cmd.ExecuteNonQuery();
            
            CloseCnn();
        }
        
        //standard dataset function that finds and 
        //return the detail of a customer in a dataset
        public DataSet Find(String argStr)
        {
            DataSet ds=null;

            try
            {
                OpenCnn();
            
                String selectStr = "select * from " + thisTable + 
                              " where cus_ID = '" + argStr + "'";
                OleDbDataAdapter da = 
                       new OleDbDataAdapter(selectStr,cnn);
                ds = new DataSet();
                da.Fill(ds,thisTable);
            
                CloseCnn();

                
            }
            catch(Exception e)
            {
                String Str = e.Message;
            }

            return ds;
        }

        private void OpenCnn()
        {
            // initialise connection
            String cnnStr = CnnStr;
            cnn = new OleDbConnection(cnnStr);
            // open connection
            cnn.Open();
        }

        private void CloseCnn()
        {
            // 5- step five
            cnn.Close();
        }
        
        // just a supporting function that builds 
        // and return the insert string for dataset.
        private String BuildAddString(BOCustomer cus)
        {
            // these are the constants as 
            // set in the top of this module.
            strTable="Insert into " + thisTable;
            strFields=" (" + cus_ID + 
            "," + cus_LName + 
            "," + cus_FName + 
            "," + cus_Address + 
            "," + cus_Tel + ")";
            
            //these are the attributes of the 
            //customer business object.
            strValues= " Values ( '" + cus.cusID + 
            "' , '" + cus.LName + 
            "' , '" + cus.FName + 
            "' , '" + cus.Address + 
            "' , '" + cus.Tel + "' )";

            insertStr = strTable + strFields + strValues;
            
            return insertStr;
            
        }
    }
}
Read more ...

Contact Us

Name

Email *

Message *