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

Build a Pluggable Application with IoC Container

4.00/5 (6 votes)
7 Apr 2012CPOL3 min read 29.1K   360  
In this article, I will show how to build a pluggable application with IoC container.

Introduction

When we build an application, we always face a lot of changes during and after application development. To be ready for changes in advance is a key character of a flexible application. IoC container stands for Inversion of Control container. It is used frequently in situations where we don’t want to directly hardcode the logic of instantiate an implementation of contract/interface in our application. By following contract first design principle and relaying the instantiation responsibility to IoC container, we can create an extensible and flexible application.

Demo Application

Suppose we want to design an application that can output text to different output channel, such as file output channel and console output channel. What we can do first is to define an output contract, so the main application will follow the contract to output text without knowing specific output channel.

C#
public interface IOutputService
{
    void WriteLine(string data);
}

After we have the contract defined, we can have two different implementations as file output channel and console output channel:

FileOutput:

C#
public class FileOutput: IOutputService
{
    public void WriteLine(string data)
    {
        using (StreamWriter sw = new StreamWriter("test.txt", false))
        {
            sw.WriteLine(data);
        }
    }
}

ConsoleOutput:

C#
public class ConsoleOutput: IOutputService
{
    public void WriteLine(string data)
    {
        Console.Write(data);
    }
}

The easiest way to get an output channel in application is to have a channel factory that will create an instance of requested output channel. However, by doing this, we hardcode the instantiation logic inside our application. If we want to add a new output channel, such as network output channel, then our only opinion is to change the code.

Make the Demo Application Pluggable

With the help of IoC container, we can easily create a pluggable application without much coding. The idea is to define a base library that will have an API like this:

C#
public interface IIoCContainer
{
    T Resolve<t>();
    IEnumerable<t> ResolveAll<t>();
}

This API gives application a way to retrieve a single instance or a collection of instances of specified type, so you can use the IOutputService interface to get a specific output channel. The IoC container API allows us to use any IoC container, such as Unity or StructureMap. At the moment of application starting up, we use BootStrapper to setup IoC container.

BootStrapper:

C#
public class BootStrapper
{
    public static void StartUp()
    {
        RegisterIoCContainer();
    }

    private static void RegisterIoCContainer()
    {
        ObjectFactory.Initialize(x => { x.PullConfigurationFromAppConfig = true; });
        IoC.IoCContainerManager.IoCContainer = new StructureMapIoCContainer();
    }
}

Initialize IoC container with BootStrapper.

C#
BootStrapper.StartUp();

After IoC container is initialized, application can directly use IoC container API to get IOutputService.

C#
IEnumerable<ioutputservice> outputServices = 
          IoC.IoCContainerManager.IoCContainer.ResolveAll<ioutputservice>();
outputServices.ToList().ForEach(o => o.WriteLine("Hello World!"));

In order to make our application more flexible and allow us to switch different output channel in production environment without recompilation, I decided to not directly reference output channel implementation in main application.

Image 1

The output channel implementation will be copied into main application via Post-build event command line.

Image 2

And the mapping between IOutputService and actual implementation is defined in application configuration file.

XML
<configSections>
    <section name="StructureMap" 
      type="StructureMap.Configuration.StructureMapConfigurationSection,StructureMap"/>
</configSections>

<StructureMap>
    <PluginFamily Type="OutputService.IOutputService" 
             Assembly="OutputService" DefaultKey="Default">
      <Plugin Type="FileOutput.FileOutput" 
             Assembly="FileOutput" ConcreteKey="Default"/>
      <Plugin Type="ConsoleOutput.ConsoleOutput" 
             Assembly="ConsoleOutput" ConcreteKey="Console"/>
    </PluginFamily>
</StructureMap>

How the Whole Application Works

When calling IoCContainer.ResolveAll<ioutputservice>(), the application will relay the call to IoC container, then IoCContainer will be based on mapping in configuration file to get specific implementation.

Image 3

After getting a collection of IOutputService, call WriteLine of IOutputService to write “Hello World” to every output channel.

Image 4

Summary

With the help of IoC container, we can quickly implement a simple pluggable application. This pluggable application can utilize configuration file to add new implementation for defined contract without changing code.

Using the Code

The code is developed in Visual Studio 2010. You can create your own IOutputService implementation and add into configuration file to experiment with the demo application.

License

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