There are many different patterns for objected oriented development that have emerged over the years.  More often than not I will stumble across one that we are inadvertently using in our services or applications at REJIS.  Most recently I wrote about an approach we use when we need a service client that will take data from a service and transform or adapt it to another format (database, xml model, fixed length file, etc).  At the core of that pattern is dependency injection.

Martin Fowler has an excellent (and lengthy) discussion on Inversion of Control and Dependency Injection which is well worth the read.  Wikipedia defines dependency injection as "...the process of supplying an external dependency to a software component. It is a specific form of inversion of control where the concern being inverted is the process of obtaining the needed dependency." 

For example lets say that you have an interface, IMyInterface, which Class A depends on for some functionality.  Class B and C both implement IMyInterface making them substitutable for Class A's dependency.  At runtime, through configuration or programmatically, you can decide which concrete class (B or C) for Class A to use.  Rather than having Class A directly depend on Class B or C you reduce coupling by relying on the interface and then you inject this dependency at runtime.

Interfaces represent one of the best possible abstractions available to an object oriented programmer.  The benefits to using interfaces and dependency injection are numerous:

  • By using an interface you have defined a contract of expected behavior for implementers.
  • Interfaces reduce coupling, allowing for independent unit testing, and multiple implementations of the interface.
  • Code becomes simplified and focused by reducing branching logic and overall lines of code.
  • Changes to the application can potentially be applied at runtime (if this is a web app, windows apps would require closing and reopening) and would not require a recompile of the entire application (if the new implementing class is in another assembly only that assembly needs to be compiled).
  • The application will be more "plug and play" and allow for adding or removing functionality as needed.

MSDN has an article that discusses Dependency Injection in depth and how it relates to a few other Creational patterns such as factory.  There are a number of Inversion of Control (IOC) frameworks that assist with dependency injection that use the notion of containers which help manage the lifecycle of objects and apply configuration settings to modify behaviors at runtime.  For a list of open source IOC frameworks check out this post by Scott Hanselman.

Dependency Injection Example - Supporting Multiple Authentication Methods

I have created a sample project which I will use to illustrate the flexibility of this approach.  The sample covers a very common scenario where we must support multiple authentication methods to allow flexibility for our customers.  We'll look at a traditional approach and then an updated approach that will use Dependency Injection.

At the core of this example is the IAuthenticator Interface and the User Class.  Both are very simple for examples sake.

Public Interface IAuthenticator
    Function Authenticate(ByVal userName As String, _ 
ByVal password As String) As User End Interface
Public Class User
    Public Name As String
    Public AuthenticationType As String
    Public IsAuthenticated As Boolean
End Class

The customer requested that the application first be built to support Database Authentication.  Because our architect was thinking ahead and at least forced us to use an interface we will implement that interface in our DatabaseAuthenticator class.

Public Class DatabaseAuthenticator
    Implements IAuthenticator

    Public Function Authenticate(ByVal userName As String, _
      ByVal password As String) As User Implements IAuthenticator.Authenticate
        Dim user As New User
        user.AuthenticationType = "DatabaseAuthentication"
        'Simulate DB authentication
        If userName = "Test" AndAlso password = "Testing!" Then
            user.IsAuthenticated = True
            user.Name = userName
            'else
            'could throw security exception or any other action here.
        End If

        Return user
    End Function
End Class

To test our authentication we'll go "old school" with a little console program action.  The console program will display a username prompt and password prompt then it will invoke our IAuthenticatorInstance to perform the authentication. 

Let's first look at life without dependency injection:

Module Module2

    Sub Main()
        Dim authenticator As Authenticator.IAuthenticator

        Select Case My.Settings.AuthenticationType
            Case "Database"
                authenticator = New Authenticator.DatabaseAuthenticator
            Case Else
                Throw New ArgumentException("Invalid AuthenticationType!")
        End Select

        Dim userName As String
        Dim password As String
        Dim user As Authenticator.User

        Console.WriteLine("Username: ")
        userName = Console.ReadLine

        Console.WriteLine("Password: ")
        password = Console.ReadLine

        Console.Clear()

        user = authenticator.Authenticate(userName, password)

        If user.IsAuthenticated Then
            Console.WriteLine(String.Format("User authenticated via {0}!", _
                       user.AuthenticationType))
        Else
            Console.WriteLine("User authentication failed!")
        End If

        Console.ReadLine()
    End Sub

End Module

In order for Module2 to work we've had to hard-code a string value in our case statement to help us decide the type we want to create.  From there we instantiate the appropriate class manually.  This works fine; it will run and there are no problems with it...until you need a new authentication method.  Then you must go back and add a new class that implements IAuthenticator, add a branch to the Case statement and then instantiate your new class.  Of course you could do this without interfaces as well...but I digress. 

On to life with dependency injection:

Module Module1

    Sub Main()
        Dim authenticatorType As System.Type = _
         Type.GetType(My.Settings.AuthenticatorType)
        Dim authenticator As Authenticator.IAuthenticator = _
         Activator.CreateInstance(authenticatorType)
        Dim userName As String
        Dim password As String
        Dim user As Authenticator.User

        Console.WriteLine("Username: ")
        userName = Console.ReadLine

        Console.WriteLine("Password: ")
        password = Console.ReadLine

        Console.Clear()

        user = authenticator.Authenticate(userName, password)

        If user.IsAuthenticated Then
            Console.WriteLine(String.Format("User authenticated via {0}!", _
              user.AuthenticationType))
        Else
            Console.WriteLine("User authentication failed!")
        End If

        Console.ReadLine()
    End Sub

End Module

You probably noticed the first line where we dim up the authenticator variable by calling Activator.CreateInstance and passing it a type variable which I resolved using the Type.GetType method.  Type.GetType(string) returns the System.Type which we can then pass to activator to get our instance created.

Our settings file contains this section:

<applicationSettings>
    <DepdencyInjectionConsole.My.MySettings>
        <setting name="AuthenticatorType" serializeAs="String">
            <value>Authenticator.DatabaseAuthenticator, Authenticator</value>
        </setting>
    </DepdencyInjectionConsole.My.MySettings>
</applicationSettings>

The notation I used for the type information is the standard "Class, Assembly".  Note that I am not using strong names so it is not necessary to include version and public key information.  Also note that none of the code in Module 1 references the concrete class DatabaseAuthenticator.

You may have also noticed that, including whitespace, Module1 has 29 lines versus Module2's 36 lines of code (excluding line continuations).  In our simple example 7 lines isn't much but in complex systems that factor could be easily multiplied by 10 or more.

The code that was written for Module1 has no dependencies other than it has to know about Authenticator.IAuthenticator.  The true dependency is injected at runtime.  If we try to use a type in the AuthenticatorType setting that the system cannot resolve then our program will blow up. 

Which leads us to the paradigm shift; you have to be aware of your operating environment and ensure that the assemblies you need are available in the GAC or in your applications executing or bin folder (for web apps and IIS hosted services).  This does not negate managing your dependent assemblies but it shifts it from something necessary throughout development to something that could potentially only happen during deployment.  Because the code only depends on the Interface IAuthenticator two completely different teams could be coding the main module and an IAuthenticator implementation.  Development for Module2 is more susceptible to breaking changes because of direct dependencies on the classes that implement IAuthenticator.

Adding Another Authenticator Implementation

The customer you wrote this system for now wants to add authentication that will read an XML document for user accounts.  We create a new assembly called CustomAuthenticator and our new class looks like this:

Public Class XmlAuthenticator
    Implements Authenticator.IAuthenticator
    Private Shared authenticationStore As Xml.Linq.XDocument

    Sub New()
        authenticationStore = _
        Xml.Linq.XDocument.Load("C:\Temp\AuthenticationStore.xml")
    End Sub

    Public Function Authenticate(ByVal userName As String, _
      ByVal password As String) As Authenticator.User _
      Implements Authenticator.IAuthenticator.Authenticate

        Dim user As New Authenticator.User
        Dim userQuery = From u In authenticationStore...<users>...<user> _
         Where u...<name>.Value = userName _
         And u...<password>.Value = password _
         Select u

        user.AuthenticationType = "XmlAuthentication"
        user.IsAuthenticated = userQuery.Count = 1
        If user.IsAuthenticated Then
            user.Name = userName
        End If

        Return user
    End Function
End Class

The XmlAuthenticator uses an XML file to store user accounts and loads in its constructor.  Using LINQ we query the XML document to find if our user exists.  This class resides in a completely separate assembly. 

If you are adept at reading LINQ XML Queries you can guess the documents structure:

<?xml version="1.0" encoding="utf-8" ?>
<users>
    <user>
        <name>Test</name>
        <password>Testing!</password>
    </user>
</users>

Adding XmlAuthenticator to Module2 (Anti-Dependency Injection Module)

In order to implement this in Module2 we need to add a branch to our case statement:

Case "XML"
    authenticator = New CustomAuthenticator.XmlAuthenticator

Total cost - two lines of code, another hard-coded string, someone has to update the config file and deploy the new assembly.

Adding XmlAuthenticator to Module1 (Pro-Dependency Injection Module)

In order to implement this in Module1 we need to...do nothing.  Not programmatically anyhow, but we do need to update our AuthenticatorTypeValue in the app.config.

Here's the new config:

<applicationSettings>
    <DepdencyInjectionConsole.My.MySettings>
        <setting name="AuthenticatorType" serializeAs="String">
            <value>CustomAuthenticator.XmlAuthenticator, CustomAuthenticator</value>
        </setting>
    </DepdencyInjectionConsole.My.MySettings>
</applicationSettings>

Total cost - zero lines of code and someone has to update a config file and deploy the new assembly.  Less work and less code to maintain.  Ladies and gentlemen I think we have a winner here!

This is a very simple example that hopefully illustrated what you can achieve using dependency injection.  The code is simply for illustration and I do not recommend or condone anyone using for their authentication components (nor will I be liable for anything you do with this)!

What are some real world ways we use this?

For service clients where we are responsible for retrieving data from a service and doing something with it we use dependency injection for what we our "adapters".  The adapters take a known type from a service and do whatever is needed; store data in a database, flat file, or another XML format.

For a service we are developing on a statewide data sharing project dependency injection is being used to allow for a custom implementation of activities within that service so that the service can be deployed to another geographical region in the state and customized via configuration.  The major functionality points were identified and abstracted with interfaces so the functionality could be implemented in different ways for the two regions.  This also allows a separate code base that the other region can maintain and update as needed.  The core functionality is completely similar between each region and should require no modification except any bugs that may surface.

We will also use this approach on another service to allow a custom "path" for a document that we will receive from an external source.  We have cases where, depending on what external partner sends us information, we need to do multiple things with it and this can vary from partner to partner.  This last example may require a more sophisticated method so I am leaning towards the Unity Framework from Microsoft as we already use Enterprise Library extensively in our services.

Another Tool in the Toolbox

The best way to look at all of these object-oriented approaches is that they are tools in your toolbox.  I will likely not use dependency injection everywhere.  But in the work I do with services we need this pattern more often than not.  Hopefully this gives you enough insight to decide if you may be able to benefit from using it in your own applications.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by: Chris
Posted on: 12/23/2008 at 8:33 PM
Tags: , , ,
Categories: Architecture
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (2) | Post RSSRSS comment feed
 
 

Related posts

Comments

Chad DeBauch us

Wednesday, December 24, 2008 12:14 PM

Chad DeBauch

Interesting article. The current project I am working on is using the SpringFramework for dependency injection and aop. It has made our code much more manageable and easier to unit test.

edmond us

Wednesday, December 31, 2008 6:23 AM

edmond

Dependency injection is getting allot of publicity of late and I agree. So now that we know loosely coupled is the way to go most times (unless quick dirty) and that .NET does not support multiple inheritance maybe we can all start to look at those patterns that empower us to reuse firm logic that moves us in the proper direction --- some of my favs. decarator and factory. But then again there are those times where I question if I am just doing this to make the code text book and not looking at the ramifications of layers and abstraction. dont know.. continueing to learn and get better.

Add comment


(Will show your Gravatar icon)  

  Country flag

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview

Friday, July 03, 2009 6:38 PM