Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

Inversion of Control – Dependency Inversion Principle – Castle’s Windsor/MicroKernel

Recently I started playing with Castle's Windsor and MicroKernel Inversion of Control Container. MicroKernel is the IOC Container while Windsor helps with external configuration needs such as loading component configurations from an XML file. Although I have yet to use ( decide on ) an IOC Container as part of my default application architecture, I can't help but be impressed with what these tools bring to the table.

Sample Application

If we take a very simple "web application" as shown below, we have an application that is dependent on a blog service. It is not dependent on a particular service / class, only on a service contract represented by IBlogDataService.

 

 

 

For simplicity, the contract is very basic-

 

public interface IBlogDataService
{
    Blog GetBlogByBlogId(int blogId);
}

 

 The Default.aspx page requests the unknown blog service from its purely fabricated, well-known service locator, AppServiceFactory:

 

IBlogDataService service = AppServiceFactory.Instance.Create<IBlogDataService>();

 

AppServiceFactory is a very minimal looking singleton that delegates all the work to Windsor / MicroKernel, which gets its list of components from an XML file ( Components.xml ) that is read at runtime:

 

public sealed class AppServiceFactory
{
    private static AppServiceFactory _instance = new AppServiceFactory();
    IWindsorContainer _container = new WindsorContainer(new XmlInterpreter("Components.xml"));
    
    public static AppServiceFactory Instance
    {
        get { return _instance; }
    }
    
    public T Create<T>()
    {
        return (T)_container[typeof(T)];
    }
    
    private AppServiceFactory()
    {
    }        
}

 

The XML file hides the services and their dependencies:

 

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <properties>
        <connectionString>myConnectionString</connectionString>
    </properties>
    <components>
        <component id="SqlDatabase"
                        service="BlogDataServices.IDatabase, BlogDataServices"
                        type="DatabaseServices.SqlDatabase, DatabaseServices">
            <parameters>
                <connectionString>#{connectionString}</connectionString>
            </parameters>
        </component>
        <component id="MyBlogDataService"
                        service="WebApplication1.IBlogDataService, WebApplication1"
                        type="BlogDataServices.MyBlogDataService, BlogDataServices" lifestyle="transient" />
        <component    id="HerBlogDataService"
                        service="WebApplication1.IBlogDataService, WebApplication1"
                        type="BlogDataServices.HerBlogDataService, BlogDataServices" lifestyle="transient">
            <parameters>
                <connectionString>#{connectionString}</connectionString>
            </parameters>
        </component>
    </components>
</configuration>

 

Dependency-Inversion Principle and Separated Interface

If we forget about the XML file for a moment and just concentrate on the graphic of the solution above, there is some really warm and fuzzy object-oriented principles and best practices happening that the container allows us to achieve.

First, is the Dependency-Inversion Principle. Rather than the application being dependent on the blog services and the blog services dependent on the database, we have inverted the relationship. The details are no longer in control of the application. The database is dependent on the blog services and the blog services is dependent on the application, allowing us to plug-in various databases and blog services at will without touching the application.

Second, this is all possible due to the use of Separated Interface. The implementation of an interface contract is located separately from the concrete implementations that implement it. Although this is not necessary to achieve our goal of dependency-inversion, is does achieve looser coupling between the parts of the application.

 

Plug-Ins

One of the beauties of these containers is that they provide a pluggable architecture, allowing you to modify an xml file that specifies chosen implementations of service contracts.

The XML file allows me to swap out MyBlogDataService

 

<component id="MyBlogDataService"
                service="WebApplication1.IBlogDataService, WebApplication1"
                type="BlogDataServices.MyBlogDataService, BlogDataServices" lifestyle="transient" />

 

for MyBetterBlogDataService as soon as I come up with it

 

<component id="MyBetterBlogDataService"
                service="WebApplication1.IBlogDataService, WebApplication1"
                type="BlogDataServices.MyBetterBlogDataService, BlogDataServices" lifestyle="transient" />

 

No compiling is necessary.

 

Auto-Wiring of Dependencies

The other obvious benefit of these tools is that they auto-wire dependencies. SqlDatabase is dependent on a ConnectionString:

 

public SqlDatabase(string connectionString)
{
    _connectionString = connectionString;
    
}

 

 and MyBlogDataService is dependent on an implementation of IDatabase:

 

public MyBlogDataService(IDatabase database)
{
    _database = database;
}

 

When I make the following call:

 

IBlogDataService service = AppServiceFactory.Instance.Create<IBlogDataService>();

 

Windsor picks up the default IBlogDataService specified in the XML file, MyBlogDataService, and notices it is dependent on an IDatabase Service. It finds the default IDatabase Service registered, SqlDatabase, and notices it needs a Connection String. It finds the Connection String and injects it to create an instance of SqlDatabase, which is then injected to create an instance of MyBlogDataService. Genius :)

 

Getting Named Service Instances

We can go a step further and grab named instances of services if we don't want the default. Add a method to AppServiceFactory to support this-

 

public T Create<T>(string name)
{
    return (T)_container[name];
}

 

Now I can ask for HerBlogDataService by name:

 

IBlogDataService herService = AppServiceFactory.Instance.Create<IBlogDataService>("HerBlogDataService");

 

Lifestyles

MicroKernel has this cool principle of Lifestyles. By default, a component would have a Singleton Lifestyle. Hence, when you request HerBlogDataService, you will always get the same instance of HerBlogDataService on every request.

However, in the XML file above, you will notice I chose a Transient Lifestyle, which means I want a new instance for each request.

There are other lifestyles supported as well as a custom lifestyle that you specify yourself.

 

Conclusion

You gotta love these inversion of control tools. There are many to choose from if you get the itch to use them in your application architectures.

by David Hayden

 

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.

7 Responses to Inversion of Control – Dependency Inversion Principle – Castle’s Windsor/MicroKernel

  1. dhayden says:

    Scott,

    It may be an artifact as I am still tinkering with how to introduce IOC in my applications. Do you have a better way? Alternative solutions are much appreciated :)

  2. It kinda seems like the service component is one level on indirection/abstraction more than you would need – especially since your data access is already pluggable by interface. I’m wondering if this architecture is an artifact of architectures you’d use prior to the enablement that the IoC container brings.

  3. Though it might sound like a good idea, you should be wary of the named instance features of DI frameworks – at least you shoul dbe careful to create a more type-safe API around it.

    In practice, you’ll rarely – if ever – need a named instance where the name of the instance doesn’t correspond to the name of a class in your app. You see this in your example with HerBlogDataService. Using strings to identify known types is a bit too loose. It will certainly hamper type rename refactoring – regardless of how smart your refactoring tool is in regards to looking for type names in strings.

    You’d be better off changing you AppServiceFactory to:
    AppServiceFactory.Instance.Create(typeof(HerBlogDataService)

    You can get the string “HerBlogDataService” from the type passed into the Create method, and locate the instance in the container based on that string. This way, you only have to deal with late-binding code in one line of code that is restricted to the single place where the traslation between type names and strings are needed to satisfy Windsor’s own API.

  4. I’ve really been reading a lot about IoC stuff lately and this post definitely helped. Thanks.

  5. Here is your configuration in Binsor:

    import BlogDataServices
    import DatabaseServices
    
    Component(MyDatabase, IDatabase, 
       SqlDatabase).connectionString = "myConnectionString"
    Component(MyBlogDataService, IBlogDataService, MyBlogDataService)
    Component(HerBlogDataService, IBlogDataService, HerBlogDataService)
      
    
  6. Windsor Rocks, yes!
    Have you seen what I did with Binsor?

  7. Good to see you like it :).

    If you want, you can take dependency injection to an even higher level by also registrating the ASP.NET pages in the container via an HttpHandler. This way you don’t need the AppServiceFactory. All that is needed in your example is a setter property for IBlogDataService and everything is wired up automagically.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>