Search
Winners

Win Prizes

Social Presence
Twitter Twitter LinkedIn YouTube Google

Like us on Facebook
Advertisements
Top Articles Author
Fri, 24-Oct-2014 Authors
All Time Authors
Sourav.Kayal
39750
SheoNarayan
38050
Niladri.biswas
33350

Latest members | More ...


(Statistics delayed by 5 minutes)
Ads
 Article

4-Tier Architecture in ASP.NET with C#

SheoNarayan
Posted by under ASP.NET category on for Intermediate level | Views : 306498 red flag
If you found plagiarised (copied) or inappropriate content,
please let us know the original source along with your correct email id (to communicate) for further action.
Rating: 4.11 out of 5
9 vote(s)
Code Updated on 21st April 2008 to support Sorting, Paging and data manipulation through Stored Procedure in DAL

Almost all of us must have heard about 3-Tier architecture but what is this 4-Tier architecture? What are the benefits and how it is different from other architectures?

 Download source code for 4-Tier Architecture in ASP.NET with C#


Well, the architecture I am going to demonstrate here is just enhancement of 3-Tier archicture. In this architecture; you no need of writing long function parameters throughout the layers (as in traditionally 3-Tier archicture has to) and the actual objects of the application will be in a separate tier so that in future you can separately use these objects for enhancements. Change in the object definition can be done without touching the entire Business Access Layers ............

Let me explain you step-wise process of creatioin of 4-Tier architecture application.

In this application, I am going to take example of a Person that will have 3 properties: FirstName, LastName, Age. We will create a separate pages to insert these records (default.aspx) into database and list,update,delete records (list.aspx) from database.

In this application we will have following 4-Tiers
1. Business Object [BO]
2. Business Access Layer [BAL]
3. Data Access Layer [DAL]
4. UI (4-Tier) folder [UI]

Picture - 1 (Solution Explorer)



For simplicity reason, I have created separate folders for first 3-tiers into App_Code folder. You can create a separate projects for these tiers and add into forth tier (UI) solution.

Get hundreds of ASP.NET Tips and Tricks http://www.itfunda.com/aspnet-how-to-tips-and-tricks/Show/50

Lets create above tiers one by one.

Business Object [BO - Person.cs]

Create a separate folder by right-clicking App_Code folder and name it as BO. Right click this folder and create a new .cs (Class) file named Person.cs. Write following code inside it.

int m_PersonID = 0;
string m_FirstName = string.Empty;
string m_LastName = string.Empty;
int m_Age = 0;

#region Propertiers
public int PersonID
{
get { return m_PersonID; }
set { m_PersonID = value; }
}

public string FirstName
{
get { return m_FirstName; }
set { m_FirstName = value; }
}

public string LastName
{
get { return m_LastName; }
set { m_LastName = value; }
}

public int Age
{
get { return m_Age; }
set { m_Age = value; }
}
#endregion Properties

Here, we are first declaring 4 variables for corresponding properites and defining properties for them.This is your Business Object with all its properties/attributes to work with. Next step is to create Data Access Layer.

Data Access Layer [DAL - PersonDAL.cs]

The way you created BO folder inside App_Code folder, create another folder named DAL. Create a .cs file inside it and name it as PersonDAL.cs

Write following code inside it (You can copy-paste).



using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Data.SqlClient;


/// <summary>
/// Summary description for PersonDAL
/// </summary>
public class PersonDAL
{
string connStr = ConfigurationManager.ConnectionStrings["TutTestConn"].ToString();

public PersonDAL()
{

}

/// <summary>
/// Used to insert records into database
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
public int Insert(Person person)
{
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
SqlCommand dCmd = new SqlCommand("InsertData", conn);
dCmd.CommandType = CommandType.StoredProcedure;
try
{
dCmd.Parameters.AddWithValue("@firstName", person.FirstName);
dCmd.Parameters.AddWithValue("@lastName", person.LastName);
dCmd.Parameters.AddWithValue("@age", person.Age);
return dCmd.ExecuteNonQuery();
}
catch
{
throw;
}
finally
{
dCmd.Dispose();
conn.Close();
conn.Dispose();
}
}


/// <summary>
/// Update record into database
/// </summary>
/// <param name="p"></param>
/// <returns></returns>
public int Update(Person person)
{
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
SqlCommand dCmd = new SqlCommand("UpdateData", conn);
dCmd.CommandType = CommandType.StoredProcedure;
try
{
dCmd.Parameters.AddWithValue("@firstName", person.FirstName);
dCmd.Parameters.AddWithValue("@lastName", person.LastName);
dCmd.Parameters.AddWithValue("@age", person.Age);
dCmd.Parameters.AddWithValue("@personID", person.PersonID);
return dCmd.ExecuteNonQuery();
}
catch
{
throw;
}
finally
{
dCmd.Dispose();
conn.Close();
conn.Dispose();
}
}

/// <summary>
/// Load all records from database
/// </summary>
/// <returns></returns>
public DataTable Load()
{
SqlConnection conn = new SqlConnection(connStr);
SqlDataAdapter dAd = new SqlDataAdapter("LoadAll", conn);
dAd.SelectCommand.CommandType = CommandType.StoredProcedure;
DataSet dSet = new DataSet();
try
{
dAd.Fill(dSet, "PersonTable");
return dSet.Tables["PersonTable"];
}
catch
{
throw;
}
finally
{
dSet.Dispose();
dAd.Dispose();
conn.Close();
conn.Dispose();
}
}

/// <summary>
/// Delete record from database
/// </summary>
/// <param name="person"></param>
/// <returns></returns>
public int Delete(Person person)
{
SqlConnection conn = new SqlConnection(connStr);
conn.Open();
SqlCommand dCmd = new SqlCommand("DeleteData", conn);
dCmd.CommandType = CommandType.StoredProcedure;
try
{
dCmd.Parameters.AddWithValue("@personID", person.PersonID);
return dCmd.ExecuteNonQuery();
}
catch
{
throw;
}
finally
{
dCmd.Dispose();
conn.Close();
conn.Dispose();
}
}

}

In this class file, we have Insert, Update, Delete, Load methods. In this class file, first I am getting the connection string from the web.config file in a class level variable called connStr and using the same string in all my methods to open the connection.

For simplicity reason, I have not shown the code for Stored Procedure, however you can get the complete database and code by downloading the Source Code files. This was your Data Access Layer. Till now you have your Business Object and Data Access Layer ready. Now lets go to the third layer and create Business Access Layer.

Business Access Layer [BAL - PersonBAL.cs]

Again, right click App_Code folder and add a new folder named BAL. Create a new class file inside it and name it as PersonBAL.cs. Write following code inside it.


using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

/// <summary>
/// Summary description for PersonBAL
/// </summary>
public class PersonBAL
{
public PersonBAL()
{

}

/// <summary>
/// insert records into database
/// </summary>
/// <param name="person"></param>
/// <returns></returns>
public int Insert(Person person)
{
PersonDAL pDAL = new PersonDAL();
try
{
return pDAL.Insert(person);
}
catch
{
throw;
}
finally
{
pDAL = null;
}
}

/// <summary>
/// Update records into database
/// </summary>
/// <param name="person"></param>
/// <returns></returns>
public int Update(Person person)
{
PersonDAL pDAL = new PersonDAL();
try
{
return pDAL.Update(person);
}
catch
{
throw;
}
finally
{
pDAL = null;
}
}

/// <summary>
/// Load records from database
/// </summary>
/// <returns></returns>
public DataTable Load()
{
PersonDAL pDAL = new PersonDAL();
try
{
return pDAL.Load();
}
catch
{
throw;
}
finally
{
pDAL = null;
}
}

/// <summary>
/// Delete record from database
/// </summary>
/// <param name="person"></param>
/// <returns></returns>
public int Delete(Person person)
{
PersonDAL pDAL = new PersonDAL();
try
{
return pDAL.Delete(person);
}
catch
{
throw;
}
finally
{
pDAL = null;
}
}

}


Here, we are creating separate methods each for respective PersonDAL.cs methods here. As in our case we don't have any business logic, so we are just instantiating the Data Access Layer objects, using its methods and and returning to UI (fourth layer, described later on).

You must have noticed here that in the try catch block, I am just writing throw; statement. This is because when any error will occur it will be send to the calling layers (in our case UI) and there we will handle it.

Till now, we have BO, BAL and DAL ready. Now we are left with our application face, I mean UI. Lets first create default.aspx file that will contain one form and textboxs that will be used to enter records.

User Interface - [UI]-Default.aspx

Create a separate folder in your UI solution named 4-Tier and add one .aspx page called Default.aspx (Picture - 2). In this page, we will write ASP.NET code to render textboxes and buttons. OnClick event of the button we will calll AddRecords method that will ultimately insert the records into database. Below is the code to render the asp.net form.


<form id="form1" runat="server">
<div>
<p><a href="List.aspx">List Records</a></p>
<asp:Label ID="lblMessage" runat="Server" ForeColor="red"

EnableViewState="False"></asp:Label>
<table style="border:2px solid #cccccc;">
<tr style="background-color:#ECF3AB;">
<th colspan="3">Add Records</th>
</tr>
<tr>
<td>
First Name:
</td>
<td>
<asp:TextBox ID="txtFirstName" runat="Server"></asp:TextBox>
</td>
<td>
<asp:RequiredFieldValidator ID="req1" runat="Server" Text="*"

ControlToValidate="txtFirstName" Display="dynamic"></asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td>
Last Name:
</td>
<td>
<asp:TextBox ID="txtLastName" runat="Server"></asp:TextBox>
</td>
<td>
<asp:RequiredFieldValidator ID="req2" runat="Server" Text="*"

ControlToValidate="txtLastName" Display="dynamic"></asp:RequiredFieldValidator>
</td>
</tr>
<tr>
<td>
Age:
</td>
<td>
<asp:TextBox ID="txtAge" runat="Server" Columns="4"></asp:TextBox>
</td>
<td>
<asp:RequiredFieldValidator ID="req3" runat="Server" Text="*" ControlToValidate="txtAge"

Display="dynamic"></asp:RequiredFieldValidator>
<asp:CompareValidator ID="Comp1" runat="Server" Text="Only integer"

ControlToValidate="txtAge" Operator="DataTypeCheck" Type="Integer"></asp:CompareValidator>
</td>
</tr>
<tr>
<td> </td>
<td>
<asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClick="AddRecords" />
</td>
</tr>
</table>
</div>
</form>


Picture - 2 (Default.aspx)



AddRecords method


protected void AddRecords(object sender, EventArgs e)
{
//Lets validate the page first
if (!Page.IsValid)
return;

int intResult = 0;
// Page is valid, lets go ahead and insert records
// Instantiate BAL object
PersonBAL pBAL = new PersonBAL();
// Instantiate the object we have to deal with
Person person = new Person();
// set the properties of the object
person.FirstName = txtFirstName.Text;
person.LastName = txtLastName.Text;
person.Age = Int32.Parse(txtAge.Text);

try
{
intResult = pBAL.Insert(person);
if (intResult > 0)
lblMessage.Text = "New record inserted successfully.";
else
lblMessage.Text = "FirstName [<b>"+ txtFirstName.Text +"</b>] alredy exists, try another

name";

}
catch (Exception ee)
{
lblMessage.Text = ee.Message.ToString();
}
finally
{
person = null;
pBAL = null;
}
}


In the above method, I am doing following things mainly:
1. Instantiating BAL object
2. Instantiating BO object
3. Settinng properties of BO object by the textbox values
4. Calling Insert method of the BAL object and passing BO object as parameter [pBAL.Insert(person)] in try block
5. Checking for number of records affected, If the number is more than zero, I am writing Success message otherwise Duplicate records found.
6. If any layer will throw any error, I am catching it and displaying to the user in throw block.
7. Whatever objects I had instantiated, I am specifying their values to null to let the GC know that I am no more going to use them.


User Interface - [UI]-List.aspx

In this page, I am going to use a GridView to List, Modify, Sort and Delete records from the database. Create an .aspx page in the same 4-Tier folder named List.aspx (Picture - 3). Following is the code for the GridView that will do data manipulation for us.



<form id="form1" runat="server">
<div>
<p><a href="Default.aspx">Add Record</a></p>
<asp:Label ID="lblMessage" runat="Server" ForeColor="red" EnableViewState="False"></asp:Label>
<asp:GridView ID="GridView1" runat="server" CellPadding="4" ForeColor="#333333" GridLines="None"
DataKeyNames="PersonID" AutoGenerateEditButton="True" AutoGenerateColumns="False"
OnRowEditing="EditRecord" OnRowUpdating="UpdateRecord" OnRowCancelingEdit="CancelRecord"
OnRowDeleting="DeleteRecord" AllowPaging="True" AllowSorting="true" PageSize="5"
OnPageIndexChanging="ChangePage" OnSorting="SortRecords">
<FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<RowStyle BackColor="#EFF3FB" />
<EditRowStyle BackColor="#2ff1BF" />
<SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
<PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
<HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<AlternatingRowStyle BackColor="White" />
<Columns>
<asp:BoundField DataField="PersonID" HeaderText="Person ID" ReadOnly="True" SortExpression="PersonID" />
<asp:TemplateField HeaderText="First Name" SortExpression="FirstName">
<ItemTemplate>
<%# Eval("FirstName") %>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtFName" runat="Server" Text='<%# Eval("FirstName") %>'></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Last Name" SortExpression="LastName">
<ItemTemplate>
<%# Eval("LastName") %>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtLName" runat="Server" Text='<%# Eval("LastName") %>'></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Age" SortExpression="Age">
<ItemTemplate>
<%# Eval("Age") %>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtAge" runat="Server" Text='<%# Eval("Age") %>'></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Delete?">
<ItemTemplate>
<span onclick="return confirm('Are you sure to Delete?')">
<asp:LinkButton ID="lnBD" runat="server" Text="Delete" CommandName="Delete"></asp:LinkButton>
</span>
</ItemTemplate>
</asp:TemplateField>

</Columns>
</asp:GridView>
</div>
</form>


Picture - 3 (List.aspx)



On the OnRowEditing, OnRowUpdating, OnRowCancelEdit, OnSorting and OnRowDeleting events we are calling respective methods to do data manipulation. Following are codes to bind the GridView and methods that will fire on GridView events.



protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
BindGrid();
}


/// <summary>
/// Fired when Cancel button is clicked
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void CancelRecord(object sender, GridViewCancelEditEventArgs e)
{
GridView1.EditIndex = -1;
BindGrid();
}


/// <summary>
/// Fires when Edit button is clicked
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void EditRecord(object sender, GridViewEditEventArgs e)
{
GridView1.EditIndex = e.NewEditIndex;
BindGrid();
}

/// <summary>
/// Fires when Update button is clicked
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void UpdateRecord(object sender, GridViewUpdateEventArgs e)
{
int personID = Int32.Parse(GridView1.DataKeys[e.RowIndex].Value.ToString());
int intResult = 0;
GridViewRow row = GridView1.Rows[e.RowIndex];

TextBox tFN = (TextBox) row.FindControl("txtFName");
TextBox tLN = (TextBox)row.FindControl("txtLName");
TextBox tAge = (TextBox)row.FindControl("txtAge");

// instantiate BAL
PersonBAL pBAL = new PersonBAL();
Person person = new Person();
try
{
person.PersonID = personID;
person.FirstName = tFN.Text;
person.LastName = tLN.Text;
person.Age = Int32.Parse(tAge.Text);
intResult = pBAL.Update(person);
if (intResult > 0)
lblMessage.Text = "Record Updated Successfully.";
else
lblMessage.Text = "Record couldn't updated";
}
catch (Exception ee)
{
lblMessage.Text = ee.Message.ToString();
}
finally
{
person = null;
pBAL = null;
}

GridView1.EditIndex = -1;
// Refresh the list
BindGrid();
}

/// <summary>
/// fires when Delete button is clicked
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void DeleteRecord(object sender, GridViewDeleteEventArgs e)
{
int personID = Int32.Parse(GridView1.DataKeys[e.RowIndex].Value.ToString());


// instantiate BAL
PersonBAL pBAL = new PersonBAL();
Person person = new Person();
try
{
person.PersonID = personID;
pBAL.Delete(person);

lblMessage.Text = "Record Deleted Successfully.";
}
catch (Exception ee)
{
lblMessage.Text = ee.Message.ToString();
}
finally
{
person = null;
pBAL = null;
}

GridView1.EditIndex = -1;
// Refresh the list
BindGrid();
}

/// <summary>
/// Fires when page links are clicked
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void ChangePage(object sender, GridViewPageEventArgs e)
{
GridView1.PageIndex = e.NewPageIndex;
// Refresh the list
BindGrid();
}

/// <summary>
/// Fires when Columns heading are clicked
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void SortRecords(object sender, GridViewSortEventArgs e)
{
DataTable dataTable = GridDataSource();

if (dataTable != null)
{
DataView dataView = new DataView(dataTable);

dataView.Sort = GetSortExpression(e);

GridView1.DataSource = dataView;
GridView1.DataBind();
}
}

#region Private Methods

/// <summary>
/// Bind the gridview
/// </summary>
private void BindGrid()
{
GridView1.DataSource = GridDataSource();
GridView1.DataBind();
}

/// <summary>
/// Get GridView DataSource
/// </summary>
private DataTable GridDataSource()
{
PersonBAL p = new PersonBAL();
DataTable dTable = new DataTable();
try
{
dTable = p.Load();
}
catch (Exception ee)
{
lblMessage.Text = ee.Message.ToString();
}
finally
{
p = null;
}

return dTable;
}

/// <summary>
/// Get sort expression for the gridview
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
private string GetSortExpression(GridViewSortEventArgs e)
{
string sortDirection = string.Empty;
// if clicked on the same column twice then let it toggle the sort order, else reset to ascending
if (ViewState["SortExpression"] != null)
{
if (!ViewState["SortExpression"].ToString().Equals(e.SortExpression.ToLower()))
{
ViewState["SortDirection"] = null;
}
}

if (ViewState["SortDirection"] != null)
{
if (ViewState["SortDirection"].ToString().Equals("ASC"))
{
sortDirection = "DESC";
ViewState["SortDirection"] = "DESC";
}
else
{
sortDirection = "ASC";
ViewState["SortDirection"] = "ASC";
}
}
else
{
ViewState["SortDirection"] = "ASC";
}
ViewState["SortExpression"] = e.SortExpression.ToLower();

return e.SortExpression + " " + sortDirection;
}
#endregion Private Methods


Thats it!!!

Now we have done all our home work, Its time to enjoy now. Just build the application by pressing Ctrl+Shift+B, once it shows Build Succeeded in the status bar at the bottom, you are ready to enjoy your 4-Tier architecture application.

Browse it as http://localhost/4-Tier (Provided you have created "4-Tier" virtual directory in your IIS or you can choose your own virtual directory name), you should see your screens as shown above (default.aspx and list.aspx pages).

Try manipulating data and see how effectively its happening. This was a simple application, based on this architecture, you can create larger application by adding separate objects and their corresponding tiers.

In order to use namespace in different tiers, you should define your namespace in respective tiers objects and use those namespace by using statement whereever you need.

I have also attached a ready to use sample code of this example, Download it and use it!!!

Thanks & Happy Coding.
Page copy protected against web site content infringement by Copyscape
About the Author

SheoNarayan

Full Name: Sheo Narayan
Member Level: HonoraryPlatinum
Member Status: Microsoft_MVP,Administrator
Member Since: 7/8/2008 6:32:14 PM
Country: India
Regards, Sheo Narayan http://www.dotnetfunda.com
http://www.snarayan.com

Microsoft MVP, Author, Writer, Mentor & architecting applications since year 2001. Connect me on http://www.facebook.com/sheo.narayan | https://twitter.com/sheonarayan | http://www.linkedin.com/in/sheonarayan
Login to vote for this post.
Found interesting? Add this to:


Comments or Responses

Posted by: Tbroyer on: 10/24/2007

Your BO "tier" is what I call a set of DTOs (Data Transfer Objects), it's neither new nor a "tier": DTOs are used to pass data from one tier to the other: they have no embedded "business logic", they're just data "containers".

Author's response: Please see the 2nd paragraph of this article. It explains the purpose and its benefits. Thanks.

Posted by: Wesc on: 10/24/2007

This is normal, everyday 3-tier: Presentation, BLL, and DAL. The object you're passing back and forth is not a tier any more than a String or Integer would be. But, it's a fine article for someone who wants a simple explanation of DTOs.

Author's response: Please see the 2nd paragraph of this article. It explains the purpose and its benefits. Thanks.

Posted by: Damieng on: 10/26/2007

This sample suffers from both SQL injection and HTML injection making it a very insecure. Get rid of building those SQL strings and use parameterised queries and ensure that output added to the HTML is correctly HttpUtility.Encoded.

Author's response: Thanks for your feedback Damieng. Sql statement has been used here to make the tutorial simple, it is informed in the DAL description. Regards

Posted by: Amitgupta007_99 on: 10/26/2007

Basically, it's all about components. If the UI (presentation) logic is mixed up with the business (task) logic, this is going to be a bear to do. You'll have to slog through all that code and filter out the business code from the presentation code. But if you put these into separate components (n tiers), you can easily plug your business code into any type of user interface or API.

Think of each tier as a black box that only has functionality that is related to what it needs to do. The tiers can just be logical or physical. In the example above it's move a physical tiers.When it comes to performance this would be very very fast and scalable too.

There's more to it, of course, but that's the basic principle Software evolves. Build it for evolution, extensibility, scalability.......and I am very sure this 4 tier architecture will helps us a great deal in improving the future of application.

Amit P Gupta
Web Strategist
amit@r2ainformatics.com



Posted by: Vijay.a.nikam on: 12/2/2007

Good one

Posted by: Vijay.a.nikam on: 1/28/2008

Hello,
This is very good article. I have some questions.
1. Where to maintain transaction.
2. If I am using inheritance. Then their is need to create a diffent DAL classes base class and each derived cass.




Posted by: Ravimama on: 4/11/2008

Consider your BO, you have member variables. Why not expose them as public variables?

What is the exact purpose of using the properties?

Sorry if my question is too dumb. But I want to get things clear.

Posted by: SheoNarayan on: 4/11/2008

Hi Vijay.a.nikam,

For your point 1 - You can use transaction in Data Access Layer.
Point 2 - I couldn't get you.



Posted by: SheoNarayan on: 4/11/2008

HI Ravimama,

To answer your question, I will suggest to visit following link

http://www.developersdex.com/csharp/message.asp?p=1111&r=6148128
http://www.eggheadcafe.com/software/aspnet/31582165/getset-vs-public-variabl.aspx
http://channel9.msdn.com/ShowPost.aspx?PostID=299396

Thanks

Posted by: Akeenlearner on: 5/31/2008

Hi, this is good, thanks. But i have a concern. I am speaking from a Windows App point of view but have yet to try this on a web app.

Supposedly, you have created separate project for each of the Layers. Let's just say the BO and BAL are in the same project. To use your objects you would have to add reference to it. However this would result in a circular dependency which is not allowed. If you had reference the dll file instead, this would also result in a error that you have made more than a file reference to a assembly when you reference the assembly in your presentation layer.

I am referring to your statement when you mentioned "You can create a separate projects for these tiers and add into forth tier (UI) solution."

Thanks, I'm still learning

Posted by: SheoNarayan on: 6/1/2008

Hi Akeenlearner,

Thanks for your response. If you are creating separate project for all these layers, you will need following:

1. You will need to create separate projects for all layers BO, BAL, DAL, UI.
2. You will need to add reference of BO into all UI, BAL and DAL. If you will have BO and BAL into same project then you will get circular reference error.
3. Your BO is nothing but a your object Entities layer that will work as a passing objects from one layer to another layer (Mostly similar to DTO but represent all entities of your application)

Please let me know if you have still some question.

Posted by: Giff2005 on: 7/11/2008

Any real world application has Business Logic. This does not fit into the above 4 tiers, necessitating another tier - commonly known as the Business Logic Layer or BLL. Am I wrong or does this meam an implementation of the above would really be a 5 tier architecture when BLL is included. Also, the BAL does seem a bit redundant. Could there just be a DataBaseController class that takes the BOL object as a parameter and uses the DAL object to perform operations.

Posted by: SheoNarayan on: 7/11/2008

Hi Giff2005,

I guess what you are calling a BLL is nothing but BAL represented here. So all your business logic if any should be written into BAL only.

Thanks

Posted by: Chchinmaya on: 7/18/2008

Hi
This is chinmaya i understand alot from this article ......... Thank u for ur information

Posted by: Rumana on: 8/25/2008

Hi,

I understood the four tier architecture . but can u help me how to use design pattern(strategy pattern) in four tier architecture.
please reply....

Posted by: SheoNarayan on: 8/25/2008

This is not your exact answer but something that can help you.

I think I won't be able to explain these things in details right now, but you can visit http://www.developer.com/design/article.php/10925_1502691_4 to know about Strategy Design pattern that might help you to design yourself.

Will try to write article on it in future.

--
Regards,
Sheo Narayan

Posted by: Jijojosephk on: 4/1/2010

Hi Sheo,

I'm not a well experienced person but I have one concern. Can't we create a common DAL rather than creating seperate DAL for all BLL Objects? correct me if I'm wrong.

Regards,
Jijo

Posted by: SheoNarayan on: 4/1/2010

@Jijojosephk

Yes, you can do that however creating all methods related with respective BLLs will complicate your DAL and will have a lot of methods (in real time projects).

However you can have your DAL classes and to communicate with the database you can create a common class or you can use Microsoft application blocks.

Hope this helps.

Thank you.

Posted by: Ko_min_min on: 7/14/2010

if you have to put each tier in seperate machine, how can you do it?


Posted by: SheoNarayan on: 7/14/2010

@Ko_min_min:
I do not think its by default possible to keep different tiers in separate machine, however you can use remoting (an old concept), WCF Serivces, Web Service to spread the load of different tiers on different machines.

In general this is not done instead several servers are hosted with same application using load balancer.

Thank you

Posted by: Ray.chayan on: 8/21/2010 | Points: 10

Hi Sheo , I have worked in 3 tire architecture but this is new to me. Thanks 4 this.
But I have some confusion about the use of BO and BAL tires. In three tire we use 1 business object layer which is and in your code you divided it into 2 tires.
how this step modify our application and which respect?

Posted by: Mukesh.chaware@dana.com on: 2/14/2011 | Points: 25

Hi Sheo,

I wonder if you are still active on this post. Nevertheless, it is a good post capturing the basics of 4-tier. I had a query here -- though not directly related to n-tier.

Usually the .config file of the DAL project will be containing the connection-string and other such details. After deployment of application, now a person having higher-privilege rights can just go to appropriate path -- right click on the config file -- open in notepad and thus come to know sensitive data as username/password of DB from connection string and other such details.

What is the best-practice you follow to overcom such a limitation?
---
Regards,
Mukesh




Posted by: SheoNarayan on: 2/14/2011 | Points: 25

Hi Mukesh,

Yest they can go and open the .config file in notepad and see them. To overcome this problem, you can encrypt the connectionstrings part. Read this article that should help you http://msdn.microsoft.com/en-us/library/ff647398.aspx.

Thanks

Posted by: JhunCa on: 2/28/2011 | Points: 25


Dear All,
I am very new in ASP.Net, do you think I should make a class or what you called BO, DAL, BAL and UI for each Table?
Let say, I have tables for my Contact Database and they are Employee , Customer and Profile , Should I make a Class or what you called BO, DAL, BAL and UI for each table in my database?
Could you please answer and I would be very grateful if you answer my questions immediately.

Thanks and more power to DotNetFunda and the contributors also.

Jhun Ca.

Posted by: Vaniy on: 4/29/2011 | Points: 25

Hi Sheo,
if you are still active in this article, can u plz explain me.

you have used Person object to insert,update and delete and why have you used datatable for listing and binding to the Grid? why not use List of Person objects to bind to Grid, so we will be using BO in all situtation. is it bcoz data table is convinient in sorting and paging?
Thanks

Posted by: SheoNarayan on: 4/30/2011 | Points: 25

Hi Vaniy,

You are correct, just to quickly put together I have used DataTable. Ideally we can use generic list objects to bring the collection of Person from DAL through BAL and populate it to the Grid.

This article was written way back in 2007 and I guess at that time we were started talking about Generic list (if I remember correctly) Now generic list support sorting and paging as well through LINQ to it would be much easier.

Thanks!



Posted by: Siva@88 on: 5/23/2011 | Points: 25

hi sheo,
Can you please send me the code for search button in list.aspx to retrive one row from database.this will help me for my project.
Thanks in Advance.
Mail address: sivarajan.kanakasabai@gmail.com

Posted by: Utkarsh31 on: 7/26/2011 | Points: 25

This is basically:
1. Domain Models (BO)
2. Repositories (DAL)
3. Services (BAL)
4. UI

public DataTable Load() - this should return IEnumerable<Person> - this way the mapping between the DB structure and your BO remains in the DAL and the rest of the code is not aware of it.

Posted by: Vishshady on: 9/11/2011 | Points: 25

Hi i used this example to creating another application but it is giving error:while updating and deleting
updating:
Server Error in '/' Application.
Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index

Source Error:

Line 121: protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
Line 122: {
Line 123: int polno = Int32.Parse(GridView1.DataKeys[e.RowIndex].Value.ToString());
Line 124:
Line 125:


Source File: C:\Users\Sriram\Documents\Visual Studio 2010\Projects\4 layer complaint\UIcomplaintreg\Listcomplaint.aspx.cs Line: 123

Stack Trace:

[ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index]
System.Collections.ArrayList.get_Item(Int32 index) +9373696
System.Web.UI.WebControls.DataKeyArray.get_Item(Int32 index) +15
UIcomplaintreg.Listcomplaint.GridView1_RowDeleting(Object sender, GridViewDeleteEventArgs e) in C:\Users\Sriram\Documents\Visual Studio 2010\Projects\4 layer complaint\UIcomplaintreg\Listcomplaint.aspx.cs:123
System.Web.UI.WebControls.GridView.OnRowDeleting(GridViewDeleteEventArgs e) +139
System.Web.UI.WebControls.GridView.HandleDelete(GridViewRow row, Int32 rowIndex) +637
System.Web.UI.WebControls.GridView.HandleEvent(EventArgs e, Boolean causesValidation, String validationGroup) +952
System.Web.UI.WebControls.GridView.OnBubbleEvent(Object source, EventArgs e) +95
System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +37
System.Web.UI.WebControls.GridViewRow.OnBubbleEvent(Object source, EventArgs e) +121
System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args) +37
System.Web.UI.WebControls.LinkButton.OnCommand(CommandEventArgs e) +125
System.Web.UI.WebControls.LinkButton.RaisePostBackEvent(String eventArgument) +169
System.Web.UI.WebControls.LinkButton.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +9
System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +13
System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +176
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +5563


deleting:
Line 121: protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
Line 122: {
Line 123: int polno = Int32.Parse(GridView1.DataKeys[e.RowIndex].Value.ToString());
Line 124:
Line 125:

PLZ PLZ HELP

Posted by: Vishshady on: 9/11/2011 | Points: 25

oh i forgot to put datakeyname......now delete is working
but while update it is showing:
ExecuteNonQuery requires an open and available Connection. The connection's current state is closed.

Posted by: SheoNarayan on: 9/11/2011 | Points: 25

You need to ensure that your database connection is open before you execute the command. Hopefully after that it should work.

Thanks

Posted by: Santoo6185 on: 10/10/2011 | Points: 25

Hi its a nice example but im getting an error like "OBJECT REFERENCE NOT SET TO AN INSTANCE OF AN OBJECT".. wat to do... jus clear my doubt

Posted by: Varung on: 12/4/2011 | Points: 25

@Ravimama
by using properties we can get and set the values.....

Posted by: Irshadvaza on: 12/30/2011 | Points: 25

Very good post.It is very easy to understand,

Posted by: Bijay87 on: 2/19/2012 | Points: 25

Thank you for this great article. Can you tell me which kind of design pattern you used to design this application?

Posted by: Raj.Trivedi on: 2/21/2013 | Points: 25

This is an awesome article............Loved it

Posted by: Munder2013 on: 5/19/2013 | Points: 25

Thank you for this great article

Posted by: Thehulk58 on: 7/10/2013 | Points: 25

if this is a Tier architecture then what we call Layered architecture?

Posted by: Sirishathotla on: 11/4/2013 | Points: 25

how to take bll public int Insert(Person person)
{
PersonDAL pDAL = new PersonDAL();
try
{
return pDAL.Insert(person);
}
iam getting error



Login to post response

Comment using Facebook(Author doesn't get notification)