russia is waging a genocidal war in Ukraine. Please help Ukraine defend itself before russia has a chance to invade other countries.
Software, AI Innovation, and Entrepreneurial Success | Inversion of control (IOC containers) .NET IOC patterns

Inversion of control (IOC containers) .NET IOC patterns

IoC is not a new concept, however. It has been around for several years now. Using object-oriented design principles and features such as interface, inheritance, and polymorphism, the IoC pattern enables better software design that facilitates reuse, loose coupling, and easy testing of software components. This article discusses IoC and demonstrates how to use this pattern in your software design without having to implement any of the open source frameworks.

History

Inversion of Control is not a new term in computer science. According to Martin Fowlerthe etymology of the phrase dates back to 1988. It is still undecided if Inversion of Control is a design pattern, an architectural Inversion of Control is presented together with Dependency Injection as a design pattern. It is a practical example of the first five techniques mentioned. He also shows that Dependency Injection might be a design pattern, whereas Inversion of Control is implemented using Dependency Injection. In an article by Mani MalarvannanInversion of Control is presented as a design pattern using contextualized lookup. The use of a service locator is considered using the same design pattern. In an article by Robert C. Martinthe dependency inversion principle and abstraction by layering come together. His reason to use the term inversion is in comparison with traditional software development methods. He describes the uncoupling of services by the abstraction of layers, when he is talking about dependency inversion. The principle is used to find out where system borders are in the design of the abstraction layers. Inversion of Control is highly associated with dependency injection and the dependency inversion principle. Dependency injection is the main method to implement Inversion of Control. principle, or both. In an article by Shivprasad Koirala

Inversion of Control, or IoC, is an abstract principle describing an aspect of some software architecture designs in which the flow of control of a system is inverted in comparison to procedural programming.

In traditional programming the flow is controlled by a central piece of code. Using Inversion of Control this central control as a design principle is left behind.

Inversion of Control as a design guideline serves the following purposes:

  • There is a decoupling of the execution of a certain task from implementation.
  • Every system can focus on what it is designed for.
  • The systems make no assumptions about what other systems do or should do.
  • Replacing systems will have no side effect on other systems.

Implementation techniques are influenced by the computer language used.

When these containers talk about how they are so useful because they implement "Inversion of Control" I end up very puzzled. Inversion of control is a common characteristic of frameworks, so saying that these lightweight containers are special because they use inversion of control is like saying my car is special because it has wheels.

The question, is what aspect of control are they inverting? When I first ran into inversion of control, it was in the main control of a user interface. Early user interfaces were controlled by the application program. You would have a sequence of commands like "Enter name", "enter address"; your program would drive the prompts and pick up a response to each one. With graphical (or even screen based) UIs the UI framework would contain this main loop and your program instead provided event handlers for the various fields on the screen. The main control of the program was inverted, moved away from you to the framework.

For this new breed of containers the inversion is about how they lookup a plugin implementation. In my naive example the lister looked up the finder implementation by directly instantiating it. This stops the finder from being a plugin. The approach that these containers use is to ensure that any user of a plugin follows some convention that allows a separate assembler module to inject the implementation into the lister.

As a result I think we need a more specific name for this pattern. Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various IoC advocates we settled on the name Dependency Injection.

I'm going to start by talking about the various forms of dependency injection, but I'll point out now that that's not the only way of removing the dependency from the application class to the plugin implementation. The other pattern you can use to do this is Service Locator, and I'll discuss that after I'm done with explaining Dependency Injection.

The Inversion of Control (IoC), sometimes referred to as dependency injection (DI) (however, see article IoC vs DI), is a straightforward application plumbing technique based on a common programming practice. CBD frameworks that combine the declarative application descriptions and the IoC technique are referred to as IoC frameworks. Contrary to their predecessors, IoC frameworks are non-invasive and use the dependency/configuration injection/setting scenario.

.NET IOC examples:

  1. Castle Windsor
  2. Spring.NET
  3. StructureMap
  4. Unity
  5. Autofac
  6. Ninject
  7. PicoContainer.NET
  8. Puzzle.NET
  9. LinFu
  10. S2Container.NET
  11. LightCore
  12. TinyIoC
  13. Hiro

 

Analyze of perfomance IOC containers

alt text

Some usefull information and analyze IoC containers.

Digression: The Importance of Testing in Isolation

The great thing up until now, is that I've not written a single line of actual code - all I've done is define a few interfaces and basically draw up the blueprints of the application. This is important with respect to test-driven development; here I'm writing a test to help me implement the ShowPost action method on the PostController class, but to implement that method I come across dependencies to other classes (which might not even be implemented yet, as is the case here), and I need to take them out of the equation so that I can write my test without it depending on their implementations (and inherently, their correctness). Notice that I've used a mocking library (Moq) to help me accomplish this. Testing in isolation is one of the most important aspects of writing useful unit tests; I cannot stress that enough. If you don't isolate your tests and you introduce a bug somewhere, then not only the test that verifies that particular code path will fail, but loads of tests all over the place will fail because they too depend on the code containing the bug. Not only will it be much harder to track down the offending line(s) of code, but seeing a sea of tests go red doesn't exactly do wonders for your motivation either. Unit testing should be like playing reverse Domino; the goal is to not knock over any other pieces if one should tip over.

Resolving Dependencies

For our test, we manually injected the IPostRepository dependency into the PostController - but that won't do when we actually browse to the URL routed to the action; out of the box, ASP.NET MVC won't know how to create an instance of the PostController because its constructor is not parameterless. That's where an IOC container comes into the picture - it'll let us register all the dependencies our application requires in one single place, making it easy to manage and maintain them, and then it'll take care of figuring out which dependencies goes where when instantiating objects. As I mentioned previously, I really dig Autofac, so I'll be demonstrating how we'd do things using it.

Isolating the ugly stuff

For me, the DIP is all about isolating the ugly stuff.  For calculating order totals, I shouldn't be concerned about where the discounts are or how to decide what tax strategy should be used.  We did increase the number of classes significantly, but this is what happens when we move away from a procedural mindset to a true object-oriented design.

I still have the complexity to solve of pushing the dependencies into the OrderProcessor.  Clients of the OrderProcessor now have the burden of creating the correct dependency and giving them to the OrderProcessor.  But that problem is already solved with Inversion of Control (IoC) containers like Spring.NET, Windsor, StructureMap, Unity and others.

These IoC containers let me configure the "what" when injecting dependencies, so even that decision is removed from the client.  If I didn't want to go with an IoC container, even a simple creation method or factory class could abstract the construction of the OrderProcessor with the correct dependencies.

By adhering to the Dependency Inversion Principle, I can create designs that are clean, with clearly defined responsibilities.  With the dependencies extracted out, the implementation details of each dependency can change without affecting the original class.

And that's my ultimate goal: code that is easy to change.  Easier to change means a lower total cost of ownership and higher maintainability.  Since we know that requirements will eventually change, it's in our best interest to promote a design that facilitates change through the Dependency Inversion Principle.

What is IOC?

The Inversion of Control (IoC) and Dependency Injection (DI) patterns are all about removing dependencies from your code.

Inversion of Control (IoC) means that objects do not create other objects on which they rely to do their work. Instead, they get the objects that they need from an outside source (for example, an xml configuration file).

Dependency Injection (DI) means that this is done without the object intervention, usually by a framework component that passes constructor parameters and set properties.

IoC container in 15 Minutes and 33 Lines Of Code:

static class IoC 
{
   static readonly IDictionary<Type, Type> types = new Dictionary<Type, Type>();
  
   public static void Register<TContract, TImplementation>()
   {
      types[typeof(TContract)] = typeof(TImplementation);
   }
  
   public static T Resolve<T>()
   {
      return (T)Resolve(typeof(T));
   }

  
   public static object Resolve(Type contract)
   {
      Type implementation = types[contract];
  
      ConstructorInfo constructor = implementation.GetConstructors()[0];
  
      ParameterInfo[] constructorParameters = constructor.GetParameters();
  
      if (constructorParameters.Length == 0)
         return Activator.CreateInstance(implementation);
  
      List<object> parameters = new List<object>(constructorParameters.Length);
  
      foreach (ParameterInfo parameterInfo in constructorParameters)
         parameters.Add(Resolve(parameterInfo.ParameterType));
  
      return constructor.Invoke(parameters.ToArray());
   }
}

public interface IFileSystemAdapter { }
 
public class FileSystemAdapter : IFileSystemAdapter { }
 
public interface IBuildDirectoryStructureService { }
 
public class BuildDirectoryStructureService : IBuildDirectoryStructureService
{
   IFileSystemAdapter fileSystemAdapter;
   public BuildDirectoryStructureService(IFileSystemAdapter fileSystemAdapter)
   {
      this.fileSystemAdapter = fileSystemAdapter;
   }

IoC.Register<IFileSystemAdapter, FileSystemAdapter>();
 
IoC.Register<IBuildDirectoryStructureService, BuildDirectoryStructureService>();
 
IBuildDirectoryStructureService service = IoC.Resolve<IBuildDirectoryStructureService>();

You need not worry about supplying the BuildDirectoryStructureService
with an implementation for the service it depends on, but only to
register an implementation for that service.
}

For example, say your application has a text editor component and you want to provide spell checking. Your standard code would look something like this:

publicclassTextEditor
{
   
privateSpellChecker checker;
   
publicTextEditor()
   
{
        checker
=newSpellChecker();
   
}
}

What we've done here is create a dependency between the TextEditor and the SpellChecker. In an IoC scenario we would instead do something like this:

publicclassTextEditor
{
   
privateISpellChecker checker;
   
publicTextEditor(ISpellChecker checker)
   
{
       
this.checker = checker;
   
}
}

Now, the client creating the TextEditor class has the control over which SpellChecker implementation to use. We're injecting the TextEditor with the dependency.

Figure 2

 

In Java there are six basic techniques to implement Inversion of Control. These are:

  1. using a factory pattern
  2. using a service locator pattern

Figure 3

  1. using a constructor injection
  2. using a setter injection
  3. using an interface injection
  4. using a contextualized lookdown

There are three main styles of dependency injection. The names I'm using for them are Constructor Injection, Setter Injection, and Interface Injection. If you read about this stuff in the current discussions about Inversion of Control you'll hear these referred to as type 1 IoC (interface injection), type 2 IoC (setter injection) and type 3 IoC (constructor injection). I find numeric names rather hard to remember, which is why I've used the names I have here.

Service Locator vs Dependency Injection

The fundamental choice is between Service Locator and Dependency Injection. The first point is that both implementations provide the fundamental decoupling that's missing in the naive example - in both cases application code is independent of the concrete implementation of the service interface. The important difference between the two patterns is about how that implementation is provided to the application class. With service locator the application class asks for it explicitly by a message to the locator. With injection there is no explicit request, the service appears in the application class - hence the inversion of control.

Inversion of control is a common feature of frameworks, but it's something that comes at a price. It tends to be hard to understand and leads to problems when you are trying to debug. So on the whole I prefer to avoid it unless I need it. This isn't to say it's a bad thing, just that I think it needs to justify itself over the more straightforward alternative.

The key difference is that with a Service Locator every user of a service has a dependency to the locator. The locator can hide dependencies to other implementations, but you do need to see the locator. So the decision between locator and injector depends on whether that dependency is a problem.

Using dependency injection can help make it easier to see what the component dependencies are. With dependency injector you can just look at the injection mechanism, such as the constructor, and see the dependencies. With the service locator you have to search the source code for calls to the locator. Modern IDEs with a find references feature make this easier, but it's still not as easy as looking at the constructor or setting methods.

A lot of this depends on the nature of the user of the service. If you are building an application with various classes that use a service, then a dependency from the application classes to the locator isn't a big deal. In my example of giving a Movie Lister to my friends, then using a service locator works quite well. All they need to do is to configure the locator to hook in the right service implementations, either through some configuration code or through a configuration file. In this kind of scenario I don't see the injector's inversion as providing anything compelling.

The difference comes if the lister is a component that I'm providing to an application that other people are writing. In this case I don't know much about the APIs of the service locators that my customers are going to use. Each customer might have their own incompatible service locators. I can get around some of this by using the segregated interface. Each customer can write an adapter that matches my interface to their locator, but in any case I still need to see the first locator to lookup my specific interface. And once the adapter appears then the simplicity of the direct connection to a locator is beginning to slip.

Since with an injector you don't have a dependency from a component to the injector, the component cannot obtain further services from the injector once it's been configured.

A common reason people give for preferring dependency injection is that it makes testing easier. The point here is that to do testing, you need to easily replace real service implementations with stubs or mocks. However there is really no difference here between dependency injection and service locator: both are very amenable to stubbing. I suspect this observation comes from projects where people don't make the effort to ensure that their service locator can be easily substituted. This is where continual testing helps, if you can't easily stub services for testing, then this implies a serious problem with your design.

Of course the testing problem is exacerbated by component environments that are very intrusive, such as Java's EJB framework. My view is that these kinds of frameworks should minimize their impact upon application code, and particularly should not do things that slow down the edit-execute cycle. Using plugins to substitute heavyweight components does a lot to help this process, which is vital for practices such as Test Driven Development.

So the primary issue is for people who are writing code that expects to be used in applications outside of the control of the writer. In these cases even a minimal assumption about a Service Locator is a problem.

Constructor versus Setter Injection

For service combination, you always have to have some convention in order to wire things together. The advantage of injection is primarily that it requires very simple conventions - at least for the constructor and setter injections. You don't have to do anything odd in your component and it's fairly straightforward for an injector to get everything configured.

Interface injection is more invasive since you have to write a lot of interfaces to get things all sorted out. For a small set of interfaces required by the container, such as in Avalon's approach, this isn't too bad. But it's a lot of work for assembling components and dependencies, which is why the current crop of lightweight containers go with setter and constructor injection.

The choice between setter and constructor injection is interesting as it mirrors a more general issue with object-oriented programming - should you fill fields in a constructor or with setters.

My long running default with objects is as much as possible, to create valid objects at construction time. This advice goes back to Kent Beck's Smalltalk Best Practice Patterns: Constructor Method and Constructor Parameter Method. Constructors with parameters give you a clear statement of what it means to create a valid object in an obvious place. If there's more than one way to do it, create multiple constructors that show the different combinations.

Another advantage with constructor initialization is that it allows you to clearly hide any fields that are immutable by simply not providing a setter. I think this is important - if something shouldn't change then the lack of a setter communicates this very well. If you use setters for initialization, then this can become a pain. (Indeed in these situations I prefer to avoid the usual setting convention, I'd prefer a method like initFoo, to stress that it's something you should only do at birth.)

But with any situation there are exceptions. If you have a lot of constructor parameters things can look messy, particularly in languages without keyword parameters. It's true that a long constructor is often a sign of an over-busy object that should be split, but there are cases when that's what you need.

If you have multiple ways to construct a valid object, it can be hard to show this through constructors, since constructors can only vary on the number and type of parameters. This is when Factory Methods come into play, these can use a combination of private constructors and setters to implement their work. The problem with classic Factory Methods for components assembly is that they are usually seen as static methods, and you can't have those on interfaces. You can make a factory class, but then that just becomes another service instance. A factory service is often a good tactic, but you still have to instantiate the factory using one of the techniques here.

Constructors also suffer if you have simple parameters such as strings. With setter injection you can give each setter a name to indicate what the string is supposed to do. With constructors you are just relying on the position, which is harder to follow.

If you have multiple constructors and inheritance, then things can get particularly awkward. In order to initialize everything you have to provide constructors to forward to each superclass constructor, while also adding you own arguments. This can lead to an even bigger explosion of constructors.

Despite the disadvantages my preference is to start with constructor injection, but be ready to switch to setter injection as soon as the problems I've outlined above start to become a problem.

This issue has led to a lot of debate between the various teams who provide dependency injectors as part of their frameworks. However it seems that most people who build these frameworks have realized that it's important to support both mechanisms, even if there's a preference for one of them.

References:

Summary

In this article you've seen what Inversion of Control and Dependency Injection are and how they can lead to a better design of a software application. Inversion of Control (IoC) and Dependency Injection (DI) are two related practices in software development which are known to lead to higher testability and maintainability of software products. While some people employ them daily in their work, many others still don't know much about them, mostly because they require in the former a shift in the usual thinking process. IoC is a powerful way to let you tear apart the binding around your objects, and let them roam free and unencumbered. What is your favorite IOC container?

Pingbacks and trackbacks (1)+

Comments are closed