Click here to Skip to main content
Click here to Skip to main content
Go to top

An idea of a three tier application using IoC (Inversion of Control), DI (Dependency Injection), and perfectly decoupled layers

, 12 Oct 2012
Rate this:
Please Sign up or sign in to vote.
A very basic concept in developing a three tier application.

Introduction

Let's start with a very basic conception in developing a three tier application. These kinds of applications normally have three layers: Data access layer (DAL), Business Logic Layer (BLL) and the View or Presentation layer. The organization of the layers is like the picture bellow.

Fig: Old Three tier 

In this organization the BLL is directly dependent on DAL and the View layer is directly dependent on DAL and BLL layers. Here say for example a ProductService class in BLL will directly use the ProductRepository class in DAL layer like this:

public class ProductService 
{
    ProductRepository pr;
    int getProductCount()
    { 
        pr = new ProductRepository();
        return pr.getSqlProductCount();
    }
}

This is a problem; because with the direct initialization of ProductRepository in ProductService class makes them tightly coupled. At this point suppose you need to change the repository to OracleProductRepository, then you need to rewrite the ProductService class and compile again. Moreover it is also not possible to test the ProductService object without the ProductRepository object.

The same happens to the objects of the View layer which directly uses the objects of BLL and sometimes DAL. This makes View layer tightly coupled to the BLL and DAL layer which there by restricts the View layer to test without exactly that BLL and DAL layer.

Actually our problem is: all objects instantiation of DAL layer are scattered among all the objects of BLL layer and all the BLL layer objects instantiation are   scattered among all the objects of View layer objects. To solve this – somehow we will have to control the object  instantiation from one center.

The remedy:

The remedy lies in IoC and DI. So lets get familiar with those.

IoC:

Firstly to get rid from this problem we will have to use the IoC – Inversion of control. We will have to move the control of instantiation-of-objects to a separate entity – a separate object which we will call Composition Root.

DI:

Secondly, notice the Fig: Old Three tier. There the BLL depends on DAL because objects of BLL needs to instantiate the objects of DAL layer. If we can remove this dependency than we can restrict the objects of BLL to directly access the objects of DAL. But objects of BLL needs to access the DAL objects – how will they do that? Answer is by Dependency Injection and Interface.

Notice the picture bellow.

Fig: New relation between BLL and DAL

Here the BLL and DAL has their own interfaces and BLL is not depending on DAL  rather DAL is depending on BLL. Latter we will see the advantage of that.

Notice also that there is a separate object CRoot that will instantiate all the objects in DAL and BLL. Here we have moved the control of instantiation of all the BLL and DAL object, thus implemented Inversion of Control(IoC).

CRoot will also inject the DAL objects in the BLL objects while instantiation. This is called Dependency Injection (DI). Interface will be used to do that.

Have a look at the ProductService class of BLL and follow the comments.

public class ProductService : IProductService
{
  // Dependency of the DLL object will be injected here
  ISqlProductRepository sqlPrdRepo;

  // Constructor
  public ProductService(ISqlProductRepository _r)
  {
    // Injecting Dependency
    sqlPrdRepo = _r;
  }

  // Other functions coming...
}

Now the DAL object that will be injected will simply implement the Interface

public class SqlProductRepository : ISqlProductRepository 
{
    // other functions for database query
}

Notice in the Fig: New relation between BLL and DAL that DAL depends on BLL – this is because sometimes DAL need to populate the POCO (plain old CLR objects) objects or domain objects of BLL. DAL will fetch data from the Repository objects or Data layer objects and will pass these data to the BLL POCOs.

A sample POCO is as this and resides in BLL

public class Product : IProduct
{
    public string Name { get; set; }
    public int Id { get; set; }
}

And this POCO is populated in the DAL layer by SqlProductRepository object like this.

public class SqlProductRepository : ISqlProductRepository 
{
    public IEnumerable getSqlProductList()
    {
        // Making a list of POCO 
        var _l = new List()
        {
            // In practical projects this data will come from DB
            new Product(){ Name = "Xion Precessor" , Id = 21},
            new Product(){ Name = "Ci7 Precessor" , Id = 20},
            new Product(){ Name = "Seleron Precessor" , Id = 13},
            new Product(){ Name = "Ci5 Precessor" , Id = 17}
         };
        //returning the list to BLL
        return _l;
    }
}

Finally this Product list is passed to layer upwards (i.e., View layer) by the object ProductService in BLL like this

public class ProductService : IProductService
{
  // Dependency of the DLL object will be injected here
  ISqlProductRepository sqlPrdRepo;

  // Constructor
  public ProductService(ISqlProductRepository _r)
  {
    // Injecting Dependency
    sqlPrdRepo = _r;
  }

  public IEnumerable GetSqlProductList()
  {
    //  Using the dependency get the Product list and
    //  return to layer upwards
    return sqlPrdRepo.getSqlProductList();
  }
}

Here all the interfaces like IProduct, IProductService, and ISqlProductRepository will be resided in Interface layer. These interface layer is separated so that all the other layers (i.e. ,View layer) can efficiently use the interfaces rather than the original object.

Finally comes the CRoot object where the BLL object – ProductService is instantiated and the DAL object – SqlProductRepository is injected in it.

public class Root
{
  // A property as IProductService holding the ProductService  
  public IProductService ProuctService { get; set; }

  // Constructor
  public Root()
  {

     // Instantiating the DAL object
     ISqlProductRepository _repo = new SqlProductRepository();

     // Instentiating the BLL object and 
     // inject the DAL object in it
     this.ProuctService = new ProductService(_repo);

     // ... Other DLL and BAL objects instantiating       
  }
}

Now is the time to integrate the View layer or Presentation layer. This layer should only depend on the Composition Root (i.e., CRoot) and also should be perfectly decoupled from the BLL and DAL.

See the final diagram

Fig: Final View,BLL and DAL

As you see the View layer is depending on CRoot and from there it will get all the necessary BLL and DAL objects. View layer will not use these objects directly rather it will use interfaces of those objects. Thus it is perfectly decoupled from the DAL and BLL layer.

The view layer could be anything from Console Application to Web or Desktop or Mobile Application and for simplicity i am showing a console application as a view. This view layer will ask the CRoot for an instance for IProductService. Then it will use this IProductService to get the list of IProduct.

Code from the View layer

static void Main(string[] args)
{
  Root _root = new Root();
  IProductService _prdsrv = _root.ProuctService;
  List _l = (List)_prdsrv.GetSqlProductList();

  Console.WriteLine("The processor lists as bellow");
  foreach (IProduct pr   in _l)
  {
     Console.WriteLine("The product ID: " + 
       pr.Id.ToString() + " --- Name: " + pr.Name);
  }

   Console.Read();
}

There are significant advantages we will get from this design:

  1. We have centralized our object instantiation to CRoot object. So neither you can create DAL object in BLL layer nor BLL objects in View layer. Hence our code is highly maintainable and reusable.
  2. We have injected the DAL objects in to BLL objects through constructor injection from CRoot object. Hence the DAL layer is less coupled with BLL layer. Some day if we want to replace the SQL DAL layer with Oracle DAL – we’ll just have to modify the CRoot object. The new Oracle DAL will have to implement the interfaces.
  3. Our view layer is also loosely coupled with the BLL and DAL coz it is using the Interface layer to handle BLL and DAL objects.
  4. The application is easy to test. For example we can easily make a dummy DAL layer and use it in application and test.

Possible Upgrade:

Up to now we have successfully created an application where the codes are highly maintainable and reusable, the layers are perfectly decoupled and easy to test individual layer. For further improvement we can introduce a Container in the CRoot layer. The container can be any sort of – from Unity, Castle WindsorStructureMap to Spring.NET.

Final Words

The design concept is totally my own – so I will appreciate comments and criticism.

References:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

RizviHasan
Software Developer
Sweden Sweden
No Biography provided

Comments and Discussions

 
QuestionI prefer... PinmvpMehdi Gholam12-Oct-12 5:33 
AnswerFYI: The spelling in tier, not tire PinmemberClifford Nelson12-Oct-12 6:18 
GeneralRe: FYI: The spelling in tier, not tire PinmemberRizviHasan12-Oct-12 9:10 
AnswerRe: FYI: The spelling in tier, not tire PinmemberClifford Nelson12-Oct-12 12:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140921.1 | Last Updated 12 Oct 2012
Article Copyright 2012 by RizviHasan
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid