Introduction

In this installment of the series, I'll show you how you can use LinFu's Simple.IOC container to quickly add Dependency Injection capabilities to your application. I'll also discuss some of the common features found in most inversion-of-control containers and I will show you how Simple.IOC can perform those same features without forcing you to decipher its object model (or lack thereof).

Note: If you're wondering what the entire LinFu framework is about, click here.

Background

When I discovered how to write LinFu.DesignByContract1 about three years ago, I quickly realized that I needed to find a way to wrap every object that I created into a contract that LinFu.DesignByContract1 could enforce. The problem was that the only way to tie an object to a contract was to wrap it with an interceptor using LinFu.DynamicProxy upon object instantiation.

The thought of having to clutter my code with direct references to ProxyFactory and LinFu.DesignByContract didn't sound too appealing. I needed a better way to abstract the details of object construction away from the client code. The client should have no knowledge about the existence of LinFu.DesignByContract and all object instantiations should be centralized into a single source.

For me, using an inversion-of-control container was the best way to meet these requirements. I therefore set out to find a library that I could easily use without having to spend more than five minutes reading its documentation or being forced to spend even more time trying to figure out its object model. More importantly, I needed a container so simple that it required little to no configuration. The container should be able to assemble itself without requiring me to write code to wire all the dependencies together. It also shouldn't force me to spend time trying to learn someone else's XML syntax.

What About…?

I looked at various IOC containers such as Castle's Windsor container, Spring.NET and others, but they didn't meet my needs for simplicity. They all had an impressive number of features, but I knew that I wasn't going to use all of their respective feature sets. I also knew that I didn't have the time to write that many configuration files to get my application up and running. Since none of those containers fit my needs, I decided to write my own. That's how Simple.IOC came into existence.

Features and Usage

In the following sections, I'll briefly discuss the features commonly found in an IOC container and I'll show you how easy it is to implement the same features using LinFu. Before I talk about how to use Simple.IOC's features, however, we're going to need a model to use with the container. Here it is:

An Example Model

Note the following example model, in pseudo-code:

A vehicle has an engine.
A vehicle also has a driver, which is a person.
Vehicles can either move or park.
An engine can either start or stop.
A person has a name and an age.

Using this description, one can glean an object model that results in the following code:

Interfaces?

The first thing that you might notice here is that I'm actually using interfaces for the model rather than using either an abstract base class or a concrete class. Using interfaces allows you to easily use other parts of the LinFu framework (in libraries such as DynamicProxy or DynamicObject) and it gives the Simple.IOC container the most amount of flexibility when dealing with your type instances. In any case, this model should be sufficient for this discussion, so let's move on to the next section.

Object Instantiation

One of the most important features that any IOC container can provide is the ability to separate the details of object construction from its actual usage. For the Simple.IOC container, accessing an IVehicle instance is as easy as:

In this example, the client code knows nothing about the concrete class that implements the IVehicle interface. The client assumes that the container is capable of providing an IVehicle implementation, but at this point we haven't injected any dependencies into the container yet. If that's the case, then how do you inject services into the container?

Dependency Injection

In order to ensure that there is a working implementation of the IVehicle interface, we need to make sure that the container can create instances of IVehicle by providing a concrete class implementation that the container can use. Assuming that I have the following Car class defined in a DLL named CarLibrary.dll:

Most inversion-of-control containers would use an external XML file to describe what should be injected into the container. That's not the case with LinFu. LinFu, in contrast, only requires a single attribute declaration declared on each concrete class to determine which dependencies should be injected into the container. Since we are only loading CarLibrary.dll, loading that assembly is as easy as:

The loader will scan the CarLibrary.dll assembly for any types that have ImplementsAttribute defined and it will inject each of those types into the container. All you have to do is define ImplementsAttribute in your class and the loader will handle the rest. The first attribute parameter describes the interface type that your class will be implementing, while the second parameter denotes the lifecycle of the type that you wish to inject. While the first parameter is self-explanatory, the lifecycle type needs a bit more explanation.

Lifecycle Management

Like other IOC containers, LinFu supports the following lifecycle types:

Once per Request

Every time a client requests a service instance from the container, the container will create a brand new instance for your client to use. No two instances that are instantiated will ever be the same reference. In the previous example, we specified LifecycleType.OncePerRequest on the Car class to indicate that every vehicle created from that container will be a new and separate vehicle.

Once per Thread

In contrast to LifecycleType.OncePerRequest, LifecycleType.OncePerThread tells the loader to create one instance of your target type for every thread that requests an instance of an IVehicle type. This is effectively a thread-wide singleton. The corresponding declaration would be:

[Implements(typeof(IVehicle), LifecycleType.OncePerThread)]
...

If you need an application-wide singleton, on the other hand, then the next option might be what you're looking for.

Singleton Instancing

With the LifecycleType.Singleton option, no matter how many times your client code might request an instance of a particular interface, once that instance has been created by the container, you will always get the same interface instance every time the GetService() method is called. This might be useful if you have a shared component that needs to be accessed from anywhere in your application. The equivalent declaration would be:

[Implements(typeof(IVehicle), LifecycleType.Singleton)]
...

Property Setter Injection

The next thing that you might have noticed is that IVehicle was defined with two respective properties named Driver and Engine, yet none of the examples show you how to make Simple.IOC inject those dependencies into the type automatically. This is because, by default, Simple.IOC lets concrete types inject their own dependencies from the container by having them implement the IInitialize interface:

When an object is created by the container, it checks if the newly-created instance implements IInitialize. If that object implements IInitialize, the container effectively "introduces" itself to that object through the container parameter, allowing that object to initialize itself with any services that the container might already have:

Since each type is responsible for injecting its own property dependencies from the container, the container doesn't have to know anything about injecting those property dependencies into each type. This makes the code for Simple.IOC incredibly easy to maintain. It also allows you to ensure that a container has all the dependencies your components require upon initialization.

As you can see here, there's nothing special about DefaultPropertyInjector, aside from its simplicity. Once you have written your own custom implementation of IPropertyInjector, all you need to do is add it to the container's PropertyInjectors collection:

Every time the container creates a new object, it asks every IPropertyInjector instance in that collection if it can inject dependencies into that type by using the CanInject() method. Once a property injector tells the container that it can inject properties into the target type, the container calls the InjectProperties() method, leaving the injector to perform the property injection on its own.

Constructor Injection

Unlike other containers, Simple.IOC doesn't support the traditional form of constructor injection. This is because it creates an unnecessary coupling between object instantiation and object initialization. The container should know nothing about the types it creates and it should know nothing about the constructors which that type might contain. The next question you might be asking is, "If the container can only create objects with default constructors, how do I create types that don't have a default constructor?"

Creating Your Own Factory

As it turns out, Simple.IOC makes it easy to create objects that don't have a default constructor. Let's suppose, for example, that the Car class was modified to only have the following constructor:

public Car(IEngine engine, IPerson driver);

...and let's further suppose that every time there was a request for an IVehicle instance, we wanted to use whatever IEngine and IPerson implementations the container had at the time the object was created.

A Layer of Indirection

In order to create your own factory, all you have to do is implement the IFactory(Of T) interface and define FactoryAttribute on your factory class:

The only thing left to do at this point is load your custom factory into the container. Fortunately, there's no additional code that you have to write in order to make this happen. Once you call the initial Loader.LoadDirectory() method, all dependencies (including custom factories) are loaded into the container automatically. All you have to do is make sure that your custom CarFactoryassembly is placed in the same directory as the one specified in the Loader.LoadDirectory() call. The loader will take care of the rest of the details for you.

Method Call Interception

Like other containers, Simple.IOC has features that allow you to intercept method calls made to instances that the container creates. In order to intercept instances given by the container, all you have to do is implement the ITypeInjector interface:

The CanInject() method will tell the container whether or not you can provide an interceptor (presumably a proxy) for that given service type. The Inject() method will replace the service instance with an interceptor itself. Once you have written your own custom implementation of ITypeInjector, all you have to do is add it to the TypeInjectors collection that is defined on the container instance:

With this approach, transparently adding additional behavior to your interface instances becomes practically trivial when combined with LinFu.DynamicProxy. When used with LinFu.DynamicProxy, adding another set of features to an existing interface implementation only requires you to add another interceptor. I'll leave it to the reader to decide what to do with this feature. The possibilities are endless.

Extensibility

Nearly every IOC container library has at least one or two features that allow it to extend its feature set using plug-ins. In LinFu's case, the Simple.IOC container supports plug-ins through the use of the IContainerPlugin interface:

The BeginLoad and EndLoad methods will be called before and after the loader loads the list of types into the container. To implement your own plug-in, all you would have to do is write something similar to the following:

…and just as it's done with the custom CarFactory implementation, you don't need to add any additional code to load this into the container. The loader will detect the ContainerPluginAttribute declared on SamplePlugin and it will load it into the container once Loader.LoadDirectory() is called.

Points of Interest

Inversion of Control, Implement Thyself

Probably one of the most interesting things that you might notice about the Simple.IOC container is that the container itself was actually built using inversion-of-control principles. It relies heavily on interfaces to do most of its work and it truly knows nothing about the classes that implement those interfaces.

Choosing Configuration through Reflection Instead of XML

While XML is (by definition) extensible and self-describing, it seemed like some developers were reinventing the wheel by trying to describe dependencies that were already contained in every .NET assembly ever compiled. For me, it made more sense to query the existing metadata embedded in an assembly rather than parse an external XML file that had more or less the same information. Thus, I chose to skip implementing an XML-based configuration.

Coming Up in the Next Article

In Part V of this series, I'll show you how you can use LinFu.DesignByContract2 to add language-independent Design by Contract features to your favorite .NET language without having to switch to Eiffel or Eiffel.NET. LinFu.DesignByContract2 allows you to define type contracts in the following fashion:

Believe it or not, that last call to connection.Open() will never be executed. Instead, the contract verifier will throw the following exception:

The error message displayed in the exception should look familiar; it's the same one that we defined in the example above. Think about that for one second. LinFu.DesignByContract allows you to pass contracts around as simple DLL files. Unlike Eiffel, the contracts can actually be swapped between languages and passed around as reusable libraries. The onus is on you to decide what to do with this feature. Suffice it to say that after using LinFu.DbC2, you might never develop the same way again.

Nearly Transparent

Aside from the container setup code in the VB.NET example above, the client is completely oblivious to the existence of a contract. Adding new contracts is as easy as copying new contract libraries to the application directory. Once those contracts have been placed into that directory, the only thing left to do is tell the ContractLoader instance to scan the directory again. So, for those of you who are waiting to have DbC implemented in your favorite .NET language but are still waiting for Microsoft to implement it, there's no need to worry. All you have to do is to wait for Part V of this series and I'll show you how LinFu does language-independent Design by Contract. Stay tuned!

In addition, LinFu.IoC v2.0 has been outfitted with a battery of automated unit tests so you'll be able to test it with confidence. It has been rewritten from the ground up to support unit tests, and if you ever get lost in the code, you'll find that almost every class, interface, method, property and enum is filled to the brim with C# XML doc comments.

I'm currently in the process of rewriting the entire LinFu library, and this should give you an idea of where things are heading with LinFu in the future. I want to thank everyone in CP for their great feedback and support, and this is my way of giving back to the other CPians who taught me the value of writing good code. Again, thanks everyone

Hi Philip,
imagine this cenario:
1) you have 3 service factories on your container to create A B and C types respectively.
2) Service B "gets" service A, and service C "gets" service B in their respective factory Createinstance methods.
3) Unless someone explicitly "gets" service C, none of the services is created.

this is just a simple example, but if you have services loaded from external dlls you probably don't know which one to call to boostrap the "service architecture" inside the container, they are all latent. A way around this is to iterate all services inside the container and GetService all of them, or add instances instead of relying on the factory pattern.

Maybe i'm not understanding things correctly as this might not be the responsibility of the container.

1) you have 3 service factories on your container to create A B and C types respectively.
2) Service B "gets" service A, and service C "gets" service B in their respective factory Createinstance methods.
3) Unless someone explicitly "gets" service C, none of the services is created.

Let's see if I can reorder the dependencies to make sure I understand your question correctly. Based on what you've described, the order of dependencies is actually ServiceC -> ServiceB -> ServiceA.

Now, as you said, if nobody explicitly "gets" service C, then ServiceB and ServiceA will never be created. However, if I were to create ServiceB, all of its dependencies would automatically be created and initialized (or in this case, ServiceA).

The point here is that there is essentially no bootstrapping problem because a call to the container's GetService() method causes all the dependencies of a given service to be evaluated and instantiated just before that service is instantiated. In essence, what you're really looking at in terms of dependencies is what I call the "domino effect". The factory pattern is just there to ensure that all services are only created upon request, and in some ways, this makes LinFu's IoC container no more than an extensible lazy factory. It avoids dependency issues by preventing circular dependencies by design, and it also ensures that all dependencies are kept in a straight line.

The only caveat in this case, however, is that it 1) assumes that you have loaded all the necessary dependencies into the container before you make a service request, and 2) it assumes that you know which first "domino" you need to push to get the rest of the architecture up and running. When you tell the container to load all the dependencies from an external assembly, what's actually happening behind the scenes is that it's actually creating multiple IFactory instances that will be ready to instantiate the service instances you have in memory upon request, and only upon request.

Provided that you have the container configured with all the dependencies you need, the onus is really on you to decide which part of your service architecture should be activated first.

In this case, the only responsibility of the container is to do the autowiring so that you'll have all the necessary service instances ready when you decide to request one of your services from the container. IMHO, it would be completely out of LinFu's scope to tell other developers which part of their application they should activate first, so in the end, how you decide to use your own services will be up to you. HTH

I just have a few questions regarding how to design applications using the IOC principles.

1. How do you partition the application.

I've noticed in you sample applications that in addition to loading the assembly through the loader, the client application also has a direct reference to the same assembly.

Would it be possible with a different approach defining the interfaces in one assembly and their concrete counterparts in another?

Something like Vehicle.Interfaces.DLL and Vehicle.MyImplementation.DLL.

Then the client application would only have a direct reference to the Vehicle.Interfaces.DLL.

2. Public default constructor
It would be nice if the container did not require a public constructor.
If the interfaces and their default implementation were placed in the same assembly, there is nothing that stops the client code from creating an instance the "old fashion way".

3. The container as a singleton

Would it be acceptable to provide a singleton wrapper to the container?
This way I would only need to create the container once and load the external assemblies once?
Please notice that I have not examined the source code to see if there is some sort of static dependency caching going on.

I've noticed in you sample applications that in addition to loading the assembly through the loader, the client application also has a direct reference to the same assembly.

Would it be possible with a different approach defining the interfaces in one assembly and their concrete counterparts in another?

Something like Vehicle.Interfaces.DLL and Vehicle.MyImplementation.DLL.

Not only is that possible--that's the scenario that I would recommend the most. In fact, you can even split the example library into a separate DLL, and as long as you have the [Implements] attribute defined on the concrete class, the loader will still be able to pick up the concrete class implementation and load it into the container.

seesharper wrote:

2. Public default constructor
It would be nice if the container did not require a public constructor.
If the interfaces and their default implementation were placed in the same assembly, there is nothing that stops the client code from creating an instance the "old fashion way".

Well, I suppose I could do that, but it's not really my job to tell the client code (or importantly, the client developer) what it can or it cannot do with the container. I just go under the simplest assumption that anyone who uses the container is responsible enough to control the access to it. It's a slippery slope, at best. However, if you really need to create an implementation of an interface without having to define a default constructor, then you can always define your own custom factory for it. If, on the other hand, you do hit a corner case where someone tries to construct an object using the 'old fashioned way', then they automatically lose all the benefits of the IOC container, and they're pretty much on their own.

Again, simplest assumption to take is if they know enough about how to use the object from outside the container, then they should be responsible for the consequences. IMO, giving them a psychological reason to use the container rather than tying them down with technical restrictions will certainly save everyone quite a lot of coding time in the longrun.

seesharper wrote:

3. The container as a singleton

Would it be acceptable to provide a singleton wrapper to the container?
This way I would only need to create the container once and load the external assemblies once?
Please notice that I have not examined the source code to see if there is some sort of static dependency caching going on.

That's another scenario I would recommend, but I'd be careful with using it as a singleton if you plan on using more than one thread in your application--I haven't tested it for thread safety, as of yet. I can only surmise that if you decide to load it once and only once, you won't have too many threading issues unless you have some shared data being held in the singleton that you need to lock. Other than that, it should work fine, and if it doesn't, let me know, and I'll patch the SVN so that it *will* work. I hope that helps!

Hi Philip,
I think the container.GetService method should throw an exception when it cannot find the implementation of the requested interface, not just return null. The current behaviour leads to NullReference exceptions without any description if there is any problem.

What happens if you try to add two different implementation of the same interface?

Hi Philip,
I think the container.GetService method should throw an exception when it cannot find the implementation of the requested interface, not just return null. The current behaviour leads to NullReference exceptions without any description if there is any problem.

Not a problem. I'll go ahead and patch the SVN with that.

Daniel Smolka wrote:

What happens if you try to add two different implementation of the same interface?

Simple.IOC only allows one implementation per interface at a time. I designed it so that it always assumes the simplest of cases. If you need something a bit more complicated, then you can always embed some sort of IDictionary&ltstring, object&gt that holds another IContainer instance, and then use a string to distinguish between the two factory instances.

How's that validation code coming along? I've discovered how to do quite a few more things with LinFu, some of which are--for a lack of a better word--jawdropping. Anyway, let me know via personal email if you wanna swap a few more ideas. Thanks!

Sorry Philip. I've been snowed under at work the last couple of weeks - so many staff to organise, so much work to do. Anyway - I did manage to make a rough start on the validation, I'll zip it up and send it to you so you can have a look. It's pretty basic, there's not much to it but once I get a chance at it (should be over Christmas) then I'll beef it up.