Create your own light weight IOC container in .NET

Download Source Code

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 method which can either take interface or abstract class as a generic T parameter and return implementation based on my configuration and conventions.

public static  T Resolve<t>() ;

Configuration and Convention.

Following is the sample configuration xml that defines mappings between the contracts and implementation.

< component  contract ="MyServiceBase, MyLibrary"
     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.

IOC Process Flow

Component Class

Component class encapsulates information about implementation, we have three properties ImplementationType, ImplementationInstance and IsSingleton.

IOC Container

public static class  IOCContainer
{
        
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.

< configuration >
  
< 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.

 

// following will return singleton instance of MyServiceImplementation
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>() ;


No Comments