Question

I'm attempting to wrap my head around layered application architecture, and after quite a bit of reading on the subject, I've come up with some code that attempts to implement a Data Access Layer / Business Logic Layer / Presentation Layer approach. The code does what I expect, but I would love some feedback on whether I have implemented the idea successfully, or if there are any issues with my thought process.

This is the custom object I'm storing my data in:

public class SalesOrderMetaData
{
    private bool isValid;
    public bool IsValid
    {
        get { return isValid; }
        set { isValid = value; }
    }
}

Presentation Layer:

protected void Page_Load(object sender, EventArgs e)
{
    // instatiate the BLL object
    SalesOrderBLL salesOrderBLL = new SalesOrderBLL();

    // reuest the custom object from the BLL
    SalesOrderMetaData salesOrderMetaData = salesOrderBLL.GetSalesOrderMetaData("23447");

    // present a value from the custom object to the user
    Label1.Text = salesOrderMetaData.IsValid.ToString();
}

Business Logic Layer:

public class SalesOrderBLL
{
    public SalesOrderMetaData GetSalesOrderMetaData(string csono)
    {
        // instantiate the DAL object
        SalesOrderDAL salesOrderDAL = new SalesOrderDAL();

        // request the custom object from the DAL
        SalesOrderMetaData salesOrderMetaData = salesOrderDAL.GetSalesOrderMetaData(csono);

        // return the custom object to the PL
        return salesOrderMetaData;
    }
}

Data Access Layer:

public class SalesOrderDAL
{
    public SalesOrderMetaData GetSalesOrderMetaData(string csono)
    {
        // instantiate the custom object 
        SalesOrderMetaData salesOrderMetaData = new SalesOrderMetaData();

        // retrieve the data from the data source
        string sql = "IF EXISTS (SELECT * FROM sosord WHERE csono = @csono) SELECT 1 ELSE SELECT 0;";
        SqlParameter param = new SqlParameter("csono", csono);

        // set the custom object property based on the retrieved data
        // SQLUtilities.GetScalar() is a custom method that returns a SqlCommand.ExecuteScalar() object 
        salesOrderMetaData.IsValid = Convert.ToBoolean(SQLUtilities.GetScalar(sql,param)); 

        // return the custom object to the BLL
        return salesOrderMetaData;
    }
}
Was it helpful?

Solution

That is a good start. I would point a few things out though (with the knowledge that you're just learning.. so investigate these as you go):

1) Each layer is currently tightly coupled to the implementations of the layer below it. Generally you would "code against interfaces" in this instance. This means your code is coupled to the contract.. not the implementation. Not a deal breaker because you're learning.. but good to keep in mind.

2) Your data layer is all very custom. You can save yourself a lot of headaches here by investigating the use of an ORM. They take a bit of time to learn.. but WOW are they worth the maintenance hassle.

3) Generally you have Domain Models that represent the domain objects. Alot of the time these correspond directly to database tables. Then in your UI, you have ViewModels that represent the current entity within the View being rendered. This gives you the flexibility to add custom UI-based logic (validation, formatting, etc) in the ViewModels, without the Domain Models ever needing to have such specific UI concerns in them.

If you REALLY want to start thinking about design and architecture (which is fantastic! Kudos for starting to think about that stuff), then you should definitely check out things like:

SOLID Principles

ORMs

IoC/Dependency Injection Frameworks

Etc. Again, I commend you on taking the step of actually thinking about your application structure :)

OTHER TIPS

You should not allow your domain object to be set to valid by the caller. Here is your code:

public class SalesOrderMetaData
{
    private bool isValid;
    public bool IsValid
    {
        get { return isValid; }
        set { isValid = value; }
    }
}

Any of the layers could set the IsValid property to true and then when another layer asked if the object was valid, then it would incorrectly report that it was valid.

I recommend that you make the IsValid property read-only (get only). The update of the internal isValid variable should be done through a method like Validate(), like this:

public class SalesOrderMetaData
{
    private bool isValid;
    public bool IsValid
    {
        get { return isValid; }
    }
}

public void Validate()
{
    // Check business rules here and then set isValid value to true or false
}

Now the other layers cannot lie to the domain object and say that it is valid when it is potentially not, but rather can ask for the domain object to be validated via the Validate method.

Using the Validate method is not the only way to deal with this issue, but just wanted to give you an idea of how to potentially deal with it.

The code for interacting between the layers looks good.

what you have so far demonstrates a basic n-tier approach, it is a good start. Build on it from here by replacing your data access layer with entity framework code first might be easier. Also look at inversion of control containers like Unity as a way to further separate functionality / concerns

Unity here: http://msdn.microsoft.com/en-us/library/dn170416.aspx

Entity framework here: http://msdn.microsoft.com/en-us/data/ee712907

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top