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.
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>()
;