Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WTL

Four Tier IOC Application (Converted Tier Architecture)

0.00/5 (No votes)
7 May 2013CPOL3 min read 6.9K  
Four tier IOC application.

Have you ever noticed that if the business logic entities adds a member then both the database and the views will be updated? If the business logic entities adds functionality then just the view might need updating. There are plenty of times when no functionality changes at all, but our view needs to be adjusted to enhance the user experience. Doing an update to the view requires a complete update. What if you want the same functionality, but you also have users who like the old archaic looking application instead? It'd be like creating different skins depending on the user.

What if the database needs to be switched, but no other functionality should be changed? What if you want to only move a few people (like a specific branch) over at a time?

A traditional n-tier application looks like this:

The presentation layer references the business logic layer. The business logic layer references the data access layer and the data access layer connects to the database. I am calling this the Converted Tier Architecture until someone notifies me that I'm wrong. Now let me try and show you what I am trying to explain:

Here the views references the presentation layer (which I usually call the application layer). The presentation layer references the business logic layer. However, instead of the business logic layer referencing the data access layer, I have the data access layer reference the business logic layer. Then the data access layer still connects to the database.

How this works in more detail is that the views are really just concrete classes that implement interfaces that are found in the presentation layer. My IOC container will connect these two assemblies together. I can have one or more view assemblies with different "skins" and they can be switched by a simple change in a configuration file. I can mix and match multiple view assemblies and really have a lot of flexibility when it comes to determining the best user experience and can really personalize what the end user is viewing. Now, of course you have to create multiple assemblies and I don't recommend making "skins" just to make a "skin", but it has advantages in work applications. I can go to someone who uses my application and change their config, drop in the assembly and see how they react. When I'm done I can either switch it back to the original assembly or leave it as is.

The presentation layer still references the business logic layer like usual. The business logic layer no longer references the data access layer. The data access layer references the business logic layer. I use an interface that defines the connection (in this example it's a simple Linq2Sql data context). My data layer class just needs to implement the below interface and the IOC container hooks up the business logic layer with the concrete data access layer class.

VB
Public Interface IDataAccess
    Inherits IDisposable
 
#Region "Properties"
    ''' <summary>
    ''' Gets the get data context.
    ''' </summary>
    ''' <value>
    ''' The get data context.
    ''' </value>
    ReadOnly Property GetDataContext As Data.Linq.DataContext
    ''' <summary>
    ''' Gets or sets the timeout.
    ''' </summary>
    ''' <value>
    ''' The timeout.
    ''' </value>
    Property Timeout As Integer
#End Region
#Region "Functions"
    ''' <summary>
    ''' Gets the connection state of the underlying database connection.
    ''' </summary>
    ''' <returns>The <see cref="System.Data.ConnectionState" />
    ''' value of the underlying database connection.</returns>
    Function ConnectionState() As System.Data.ConnectionState
    ''' <summary>
    ''' Opens the connection.
    ''' </summary>
    ''' <remarks>This only returns true if the function was able
    ''' to connect.  If the connection was already established
    ''' then <c>false</c> would be returned since
    ''' the function did not connect when called.</remarks>
    ''' <returns><c>true</c> if this functionality was able
    ''' to connect; otherwise <c>false</c>.</returns>
    Function OpenConnection() As Boolean
    ''' <summary>
    ''' Commits to the database using the specified mode.
    ''' </summary>
    ''' <returns><c>true</c> if successful;
    ''' otherwise <c>false</c>.</returns>
    Function Commit() As Boolean
    ''' <summary>
    ''' Commits to the database using the specified mode.
    ''' </summary>
    ''' <param name="mode">The <see cref="System.Data.Linq.ConflictMode" />
    ''' that the datacontext should follow.</param>
    ''' <returns><c>true</c> if successful; otherwise <c>false</c>.</returns>
    Function Commit(mode As System.Data.Linq.ConflictMode) As Boolean
    ''' <summary>
    ''' Removes any pending updates/inserts/deletes from the underlying data connection.
    ''' </summary>
    ''' <remarks>This is a rollback of any "Transactional" data on the underlying data context.
    ''' This is not meant to be used on a multi-DataContext transaction.</remarks>
    Sub Rollback()
#End Region
End Interface

Linq2Sql entities are created with a partial class declaration. I create a new class with the same name (so they become the same concrete class) and I implement the interfaces found in the business logic layer. My application layer which only knows of the business logic layer interface entities will end up getting a concrete class from the data access layer that it never needs to reference.

I will post a complete application with notes on using this tiered architecture at another time. I'm still making it for my wife, but will create a trimmed down version for you to view soon.

License

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