Practical Dependency Injection 101

by EFVincent on 05/27/2011

In this post we take a look at dependency injection (DI). Target audience is competent .NET developers, C# specifically (but VB’ers who read C# can benefit just as much), who’ve heard of DI but haven’t gotten around to figuring out how it fits in their day to day.

What is Dependency Injection

The first question that we need to address is: What is it that DI does for us? What problem is being solved? DI is about coupling; the degree to which program unit refers to other units. In .NET the units we’re typically worried about are classes, interfaces, components, and assemblies. Dependency injection facilitates reduction these interdependencies. Are DI patterns a silver bullet? Of course not. You can always write bad code regardless of patterns. That being said, if you’re already writing decent code and have good fundamentals, but are not using DI patterns, you’ve got the opportunity to take a leap forward.

How does DI reduce help reduce coupling? The easiest way to describe it is by diving directly into an example.

Example Scenario

We’ll work on a hypothetical in-house app where the Windows AD authenticates employees, and their Windows username is used to index a database with Employee information. It’s pretty common to see stuff like this happening in-house with line of business applications.

The example uses a provider pattern – all the data access will go through a data access provider, allowing us to build a simple provider that stores records in memory during this, our prototype phase. Theoretically we’d replace this as development continued with a provider that leverages persistent storage later.

Here’s the base level example program with no consideration for dependency injection:

class Program {
    static void Main(string[] args) {

        // ** Without using an DI Container approach **

        // Create a new provider aka data access layer
        var dal = new DevDataProvider();

        // New up an employee that's supposed to represent the currently logged in user
        var e = new Employee() {
            WindowsUsername = "thanos\\efvincent",
            EmployeeId = "0001",
            FName = "Eric",
            LName = "Vincent"
        };

        // Add it to the data access layer
        dal.AddEmployee(e);

        // See if the dal can find the current user
        e = dal.GetCurrentEmployee();

        Console.WriteLine(
            "Current logged in person is: {0}", e == null ? "unknown" : e.FName);

        // End
        Console.Write("Press any key...");
        Console.ReadKey(true);

    }
}

public class DevDataProvider {
    private static readonly List<Employee> EmployeeStore = new List<Employee>();

    public Employee GetCurrentEmployee() {
        var emp = EmployeeStore.FirstOrDefault(
            e => e.WindowsUsername.Equals(GetCurrentUserName(), StringComparison.OrdinalIgnoreCase));
        return emp;
    }

    public void AddEmployee(Employee e) {
        EmployeeStore.Add(e);
    }

    public IQueryable<Employee> Employees() {
        return EmployeeStore.AsQueryable();
    }

    private static string GetCurrentUserName() {
        var wu = WindowsIdentity.GetCurrent();
        return wu == null ? string.Empty : wu.Name;
    }
}

public class Employee {
    public string WindowsUsername { get; set; }
    public string EmployeeId { get; set; }
    public string FName { get; set; }
    public string LName { get; set; }
}

In Main() we new up the data access layer, create a new employee, and add it to our store using the data access layer. At line 21 we ask the data access layer to retrieve the employee record for the currently logged in user. Looks pretty typical, so how can IoC help? Let’s look at the coupling here – what classes are dependent on what other classes?

image

Our main program depends on the DevDataProvider class, and that depends on System.Security to find the Windows username of the currently logged in user. Asking the data access layer to determine the currently logged in user isn’t the best idea, but this is blog post code created to check out dependency injection, so deal with that for the moment.

Why are these dependencies undesirable? First consider how flexible this software is. Or rather, inflexible. We created a “quick” DevDataProvider that stores stuff in a static list. As we continue to build a system, we’d have to refer to DevDataProvider from more and more classes, creating a brittle, tightly coupled system. Replacing DevDataProvider becomes more of a maintenance problem.

Next think about testability. In real life there are unit tests (there should be anyway). One reason why people find excuses not to unit test is because their code is difficult to test. In this example, if we want to test DevDataProvider.GetCurrentEmployee() we have to consider that under the covers it’s calling the Windows API to get the current username. This makes that method harder to than it needs to be.

Step One – Leveraging Interfaces

In this version, we’ve factored out an interface called IDataProvider, and one called IIdentService. The IDataProvider should be pretty obvious – but IIdentService? The idea here is to decouple from the Windows API itself. A developer should understand everywhere that the application makes contact with any external modules, including the operating system, and then consider what the repercussions of that contact are. In this example, coupling to the Windows API to get then logged in username so directly is undesirable. We want to use a service that would supply us with credentials. That way if we’re testing, we can create a fake service that provides a predictable answer, and is therefore easier to test.

Coding to an interface also allows us to radically change the behavior of the service without having to alter its dependencies. If we move to a ASP.NET environment for example, we won’t want to use the current Windows Identity, we may want to use user information from the http context.

// Interface defining an identity service
public interface IIdentService {
    string GetCurrentUserName();
}

// Implementation of an identity service that returns the current
// logged in windows username
public class WindowsIdentService : IIdentService {
    public string GetCurrentUserName() {
        var wu = WindowsIdentity.GetCurrent();
        return wu == null ? string.Empty : wu.Name;
    }
}

// Interface defining a data provider service
public interface IDataProvider {
    Employee GetCurrentEmployee();
    void AddEmployee(Employee e);
    IQueryable<Employee> Employees();
}

// Our development data provider now implements the interface
public class DevDataProvider : IDataProvider {
    private readonly IIdentService _identService;
    private static readonly List<Employee> EmployeeStore = new List<Employee>();

    public DevDataProvider(IIdentService identService) {
        if (identService == null) throw new ArgumentNullException("identService");
        _identService = identService;
    }

    public Employee GetCurrentEmployee() {
        var emp = EmployeeStore.FirstOrDefault(
                        e => e.WindowsUsername.Equals(
                            _identService.GetCurrentUserName(),
                            StringComparison.OrdinalIgnoreCase));
        return emp;
    }

    public void AddEmployee(Employee e) {
        EmployeeStore.Add(e);
    }

    public IQueryable<Employee> Employees() {
        return EmployeeStore.AsQueryable();
    }
}

We’re part of the way to where we need to be. Altering DevDataProvider to depend on the IIdentService interface frees it from a hard dependency on a particular identity implementation. The downside is we’ve made creation of the DevDataProvider a bit more complex, as we need to supply the new instance with an IIdentityService instance.

// Create a new ident service, required for the DAL
IIdentService identSvc = new WindowsIdentService();

// Create a new DAL
IDataProvider dal = new DevDataProvider(identSvc);

The DevDataProvider now takes a constructor parameter of type IIdentService. This is where the injection in dependency injection comes from. DevDataProvider has a dependency, but instead of hard coding it into the definition of DevDataProvider, we inject it. There are different ways of injecting dependencies, but constructor injection is very popular and works well in many, or even most cases.

The complexity of constructing instances increases when we add a simple logging service which logs information or errors messages.

// Interface defining a logging service
public interface ILogService {
    void LogInfo(string msg, params object[] args);
    void LogError(string msg, params object[] args);
}

// Implementation of a console logging service
public class ConsoleLogger : ILogService {
    public void LogInfo(string msg, params object[] args) {
        Console.WriteLine(
            "{0} INFO: {1}", DateTime.Now,
            string.Format(msg, args));
    }

    public void LogError(string msg, params object[] args) {
        Console.WriteLine(
            "{0} ERROR: {1}", DateTime.Now,
            string.Format(msg, args));
    }
}

The ILogService is implemented by a simple console logger. Now both the WindowsIdentService and the DevDataProvider can leverage the logger. They’re both modified to have ILogService instance injected via their respective constructors.

// Implementation of an identity service that returns the current
// logged in windows username
public class WindowsIdentService : IIdentService {
    private readonly ILogService _logSvc;

    public WindowsIdentService(ILogService logSvc) {
        if (logSvc == null) throw new ArgumentNullException("logSvc");
        _logSvc = logSvc;
    }

    public string GetCurrentUserName() {
        var wu = WindowsIdentity.GetCurrent();
        var un = wu == null ? string.Empty : wu.Name;
        _logSvc.LogInfo("Identified current user as: {0}", un);
        return un;
    }
}

// Our development data provider now implements the interface
public class DevDataProvider : IDataProvider {
    private readonly IIdentService _identService;
    private readonly ILogService _logSvc;
    private static readonly List<Employee> EmployeeStore = new List<Employee>();

    public DevDataProvider(IIdentService identService, ILogService logSvc) {
        if (identService == null) throw new ArgumentNullException("identService");
        if (logSvc == null) throw new ArgumentNullException("logSvc");
        _identService = identService;
        _logSvc = logSvc;
    }

    public Employee GetCurrentEmployee() {
        var un = _identService.GetCurrentUserName();
        var emp = EmployeeStore.FirstOrDefault(
                        e => e.WindowsUsername.Equals(un,
                            StringComparison.OrdinalIgnoreCase));
        if (emp == null) _logSvc.LogInfo("Current employee {0} not found", un);
        return emp;
    }

    public void AddEmployee(Employee e) {
        EmployeeStore.Add(e);
        _logSvc.LogInfo("Added employee with id {0}", e.EmployeeId);
    }

    public IQueryable<Employee> Employees() {
        return EmployeeStore.AsQueryable();
    }
}

Now the services are getting more robust and they’re not tightly coupled to each other, they refer only to interfaces of the services they depend on. Main() however, where construction is going on, is getting messy.

static void Main(string[] args) {

    // ** Without using an DI Container approach **

    // Create a new logging service, required for uh.. everything
    ILogService consoleLog = new ConsoleLogger();

    // Create a new ident service, required for the DAL
    IIdentService identSvc = new WindowsIdentService(consoleLog);

    // Create a new DAL
    IDataProvider dal = new DevDataProvider(identSvc, consoleLog);

Finally we’re at the point where we can see the benefit of an dependency injection container. One thing about DI containers is that they’re already written. Several mature, robust, open-source DI containers exist. We’ll use AutoFac, because that’s what I’ve been using lately. We include AutoFac using NuGet.

// Create a singleton dependency injection container
private static readonly IContainer Container = ConfigureContainer();

// Configure the container
static IContainer ConfigureContainer() {
    // This is how AutoFac works. Other DI containers have similar
    // mechanisms for configuring the container
    var bld = new ContainerBuilder();

    // Register the types that implement the interfaces that are required
    // for injection. Note that we have robust control over lifetime, in
    // this case ILogService and IIdentService will be singletons, and
    // IDataProvider will provide a new instance each time it's requested
    bld.RegisterType<ConsoleLogger>().As<ILogService>().SingleInstance();
    bld.RegisterType<WindowsIdentService>().As<IIdentService>().SingleInstance();
    bld.RegisterType<DevDataProvider>().As<IDataProvider>();
    return bld.Build();
}

static void Main(string[] args) {

    // ** Using an IoC Container approach **
    var dal = Container.Resolve<IDataProvider>();

We’ve created a static instance of IContainer (an AutoFac DI container). When we start the app we configure the container, which fundamentally consists of mapping the interfaces to concrete types that will be injected. For example, line 14 specifies that when there’s a need for an instance of ILogService, we will create an instance of ConsoleLogger. It further says that the DI container should use a SingleInstance() of ConsoleLogger. This has the effect of making ConsoleLogger a singleton. In our example, both the WindowsIdentService and the DevDataProvider will be handed the same instance of ConsoleLogger.

The magic happens when we call Container.Resolve<IDataProvider>(). The container determines what concrete class to create, and it looks for any dependencies in the constructor. It will see that to build a DevDataProvider, it needs an ILogService and an IWindowsIdentService, it will recursively resolve those as well.

These are the basics of dependency injection. Even in this simple example, it should be obvious that the components and classes that we can create can be designed with very low coupling and cohesion using this technique. There are anti-patterns for using DI as well. You should endeavor to practice this technique, do research and learn the most effective uses; there’s plenty of material out there.

I hope this example was helpful. Next post I’ll extend this sample by looking at testing, and mock objects, and how DI injection can make testing far easier.

Source code samples can be found at this bitbucket repository.

Update: Follow up post – Dependency Injection, Testing, and Mocking

{ 1 trackback }

A Taste of Dependency Injection, Testing, and Mocking
06/02/2011 at 1:46 pm

{ 5 comments… read them below or add one }

Sivakumar M 12/19/2011 at 1:07 am

Thanks for your post. It is a simple good practical example for anyone to relate to their daily work.

Kamal 12/07/2012 at 1:20 pm

Its a simple and easy to understand article. Well explained!!!!

Gary 01/31/2013 at 4:27 pm

good job thanks!

Martix 03/20/2013 at 5:03 pm

nice and clean article, thanks ;)

Dharmaraj M 06/12/2013 at 10:07 am

Neatly explained in a very simple manner, even a beginner like me could understand it.
Thank you!

Leave a Comment

Previous post: NuGet – Galleries of Geeky Goodness.

Next post: A Taste of Dependency Injection, Testing, and Mocking