Click here to Skip to main content
Click here to Skip to main content

Build a Pluggable Application with IoC Container

, 7 Apr 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
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 situation of we don’t want to directly hardcode the logic of instantiate an implementation of contract/interface in our application. By following contract first design principal and relay 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.

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:

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

ConsoleOutput:

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 API like this:

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:

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.

BootStrapper.StartUp();

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

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.

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

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

<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 based on mapping in configuration file to get specific implementation.

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

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)

Share

About the Author

Henry He
Software Developer (Senior)
United States United States
Senior Software Developer from New Jersey, USA

Have 15+ years experience on enterprise application development with various technologies.

Comments and Discussions

 
QuestionWhy not MEF? PinmemberJaxag7-Apr-12 22:28 
AnswerRe: Why not MEF? PinmemberHenry He8-Apr-12 3:39 
GeneralRe: Why not MEF? Pinmemberfmsalmeida9-Apr-12 4:24 
MEF is not an IoC container. MEF uses an IoCContainer. It is not the same. MEF brings us all the framework to discover, load and unload the plugins at runtime that an IoCContainer does not.
Please see a similar sample using MEF made by me. MEF Logger – Creating plug-ins using MEF[^]
AnswerRe: Why not MEF? Pinmemberterryterryd9-Apr-12 12:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141220.1 | Last Updated 7 Apr 2012
Article Copyright 2012 by Henry He
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid