Friday, April 23, 2010

How to decouple your application from IoC container implementation

As we all know, DI(Dependency Injection) is a form of IoC(Inversion of Control). when I use IoC Containers like Unity or Autofac to implement dependency injection, my application will be dependent on that framework, so if i decide to go for another IoC Container, I need to change a lot of things.what I want to achieve is how to make this change easier and how to decouple my application from any specific container. what i did is creating an interface to work with.


I need to add a reference to Microsoft.Practices.ServiceLocation.dll
and I make use of IServiseLocator interface in that assembly.
//IoCContainer.cs
//-----------------------------------------------------
using Microsoft.Practices.ServiceLocation;

public abstract class IocContainer
{
   public static IServiceLocator Locator;

   protected IocContainer()
   {
      Locator = CreateServiceLocator();
   }

  protected abstract IServiceLocator CreateServiceLocator();
}

public class IocContainerInitialization
{
  private static IocContainer _iocContainer;


  public static void Initialize(IocContainer iocContainer)
  {
    _iocContainer = iocContainer;
  }

  public static IocContainer IocContainer
  {
    get { return _iocContainer; }
  }
}
//-------------------------------------------------------------

//then for every IoC Container I want to use, I need to create a container //inheriting from that base IoCContainer class.

//for example, for using Autofac


//AutofacIocContainer.cs
//----------------------------------------------------------
using Autofac.Integration.Web;
using Autofac.Integration.Web.Mvc;
using AutofacContrib.CommonServiceLocator;
using Microsoft.Practices.ServiceLocation;

public class AutofacIocContainer : IocContainer
{
  protected override IServiceLocator CreateServiceLocator()
  {
    var containerBuilder = new ContainerBuilder();

    //For MVC-------------
  containerBuilder.RegisterControllers(System.Reflection.Assembly.GetExecutingAssembly());
    //------------------------------------------------
    RegisterTypes(containerBuilder);

    ContainerProvider containerProvider = new ContainerProvider(containerBuilder.Build());

    //For MVC-------------------------------
    System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory(new  AutofacControllerFactory(containerProvider));
    //---------------------------------------------------

    return new AutofacServiceLocator(containerProvider.ApplicationContainer);
}

  private static void RegisterTypes(ContainerBuilder container)
  {
    //Cache per request
    container.Register(c => new DbHelper("MyConnectionString")).As().InstancePerLifetimeScope();

    container.Register(c => new DbMapper(c.Resolve())).As();
    container.Register(c => new TagRepository()).As();
    container.Register(c => new UserRepository()).As();
  }
}
//--------------------------------------------------------------

//Then, in your Global.asax file we need to initialize our Container.


void Application_Start(object sender, EventArgs e)
{
  IocContainerInitialization.Initialize(new AutofacIocContainer());
  RegisterRoutes(RouteTable.Routes);
}

Now, if you want to switch to another IoC Container, you only need to change one line and initialize another container.

cheers!

0 comments:

Post a Comment