Create your own light weight IOC container in .NET
There are lots of very good IOC container out there like Spring.Net and Castle Windsor, however the size of those frameworks makes me nervous specially when I have a small project and I do not need all those bells and whistles that comes with those frameworks. Following post will show you how to create and use simple IOC container.
The two most important features that I need in my all projects is Service Locator and Object Resolver. In short I need a container which gives me implementation of specified interface or abstract class based on the configuration and/or convention.
What do I need from a container?
I need a simple Resolve
Configuration and Convention.
Following is the sample configuration xml that defines mappings between the contracts and implementation.
implementation ="MyServiceConcrete, MyImplementationLibrary"
singleton ="false"/>
Contract is the fully qualified type name of your interface or abstract class and implementation is the fully qualified type name of the class that implements the contract. Additionally you may specify lifecycle of implementation by defining singleton to true or false, by default singleton is true.
As shown in the flow diagram Resolve method will look into configuration for request. If it does not find in configuration then it will look into loaded assemblies for the class that implements contract and finally it will look into local assemblies.
Component Class
Component class encapsulates information about implementation, we have three properties ImplementationType, ImplementationInstance and IsSingleton.
IOC Container
{
private static readonly Dictionary<Type, Component> objectDictionary
= new Dictionary<Type,Component>() ;
private static bool loaded = false;
public static T Resolve<T>() where T: class {
Type requestedType = typeof (T) ;
if (!loaded)
loadConfiguration() ;
if (objectDictionary.ContainsKey(requestedType)){
return getImplementionFromComponent<T>(objectDictionary[requestedType]) ;
}
if (loadFromLoadedAssemblies<T>())
{
return getImplementionFromComponent<T>(objectDictionary[requestedType]) ;
}
if (loadFromLocalAssemblies<T>())
{
return getImplementionFromComponent<T>(objectDictionary[requestedType]) ;
}
Trace.TraceWarning( "{0} not found" , requestedType.Name) ;
return null;
}
private static T getImplementionFromComponent<T>(Component c)
{
if (!c.Singleton)
{
return (T)Activator.CreateInstance(c.ImplementationType) ;
}
return (T)c.ImplementationInstance ;
}
…..
}
As you can see we have a dictionary to store contract and their corresponding implementations, on first request we are going to load information from configuration and consecutive request will get instance from dictionary. You will also notice that based on your configuration setting you will get singleton or transient instance of contract implementation. For the reason of brevity I am not showing here methods to load configuration and method to load from assembly.
Source code and Usage.
Attached Source code contains IOCContainer and a TestProject, if you want to use IOCContainer in your project then you will have to add reference to IOCContainer dll and following configuraiton section in your App.config or Web.config file.
< configSections >
< section name ="IOCConfiguration"
type ="Jigar.Infrastructure.IOCCOntainerConfigurationSectionHandler
,Jigar.Infrastructure"/>
</ configSections >
< IOCConfiguration >
< component contract ="IMyService, MyLibrary"
implementation ="MyServiceImplementation, MyImplementationLibrary" />
< component contract ="MyServiceBase, MyLibrary"
implementation ="MyServiceConcrete, MyImplementationLibrary"
singleton ="false"/>
</ IOCConfiguration >
</ configuration >
Based on the above configuration you can use following methods to resolve your service.
IMyService myService = IOCContainer<IMyService>() ;
// following will return Transients instance of MyServiceConcrete
MyServiceBase serviceBase = IOCContainer<MyServiceBase >() ;
// if you implementaion of IDynamicService in your loaded assemblies or
// local assemblies following method will return first available instance of class
// which implements IDynamicService
IDynamicService service = IOCContainer<IDynamicService>() ;