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
Posted
Fri, Oct 13 2006 8:37 PM
by
David Hayden