Caliburn Micro and inversion of control using Ninject

Caliburn Micro comes with it’s own built in mechanism for creating objects as and when required. However it’s bootstrapper comes with methods which allow us to override the default behaviour. The methods such as GetInstance, GetAllInstances and BuildUp are used to resolve dependencies in a user supplied IoC container.

I’m the built in mechanism is more than adequate for most peoples usage, but I tend to rather like Ninject. So here are the steps (which ofcourse can be used with your own preferred IoC framework).

Create a bootstrapper as per the following (where ShellViewModel is replaced with your view model name)

public class AppBootstrapper : Bootstrapper<ShellViewModel>
{
   protected override void Configure()
   {
   }

   protected override void OnExit(object sender, EventArgs e)
   {
   }

   protected override object GetInstance(Type service, string key)
   {
   }

   protected override IEnumerable<object> GetAllInstances(Type service)
   {
   }

   protected override void BuildUp(object instance)
   {
   }
}

These are the methods we need to override and implement the code for, to allow Caliburn Micro to use our preferred Ioc framework.

Configure

The configure method is used to configure Caliburn Micro to use our IoC framework, so basically this is where we instantiate the StandardKernel in Ninject. Firstly add a class level variable as follows

private IKernel kernel;

Next override the Configure method to both create the kernel and set-up default bindings

protected override void Configure()
{
   kernel = new StandardKernel();

   kernel.Bind<IWindowManager>().To<WindowManager>().InSingletonScope();
   kernel.Bind<IEventAggregator>().To<EventAggregator>().InSingletonScope();
}

We’re going to want to have access to the WindowManager and EventAggregator within our code, so we’ll set up the bindings for them. If we’re passing a class to the generic argument of the Bootstrapper this this is enough code for the Configure method, but if, as I often prefer, we have something like

public class AppBootstrapper : Bootstrapper<IShellViewModel>

i.e. an interface passed as the generic argument, then we need to also set up the bindings within Ninject to resolve this interface. Hence adding the line

kernel.Bind<IShellViewModel>().To<ShellViewModel>().InSingletonScope();

to the end of the Configure method.

OnExit

Now we’ve created the instance of the kernel, the OnExit method allows us to place cleanup code such as

protected override void OnExit(object sender, EventArgs e)
{
   kernel.Dispose();
   base.OnExit(sender, e);
}

This is (as you can see from the arguments, a event handler that Caliburn Micro hooks up to the Application.Exit event.

GetInstance

This must be overridden when providing our own IoC container. The method is used get the service for a given service, so we can simply call the following

protected override object GetInstance(Type service, string key)
{
   if (service == null)
      throw new ArgumentNullException("service");

   return kernel.Get(service);
}

GetAllInstances

This method must be overridden when supplying our own IoC container and is used to get all instances of a service. We can override it thus

protected override IEnumerable<object> GetAllInstances(Type service)
{
   return kernel.GetAll(service);
}

BuildUp

Finally, and again required when supplying our own IoC container, we need to override the BuildUp method. This is used inject instances into the IoC container and can be written as

protected override void BuildUp(object instance)
{
   kernel.Inject(instance);
}

Full Code

The full code for this is as follows

public class AppBootstrapper : Bootstrapper<ShellViewModel>
{
   private IKernel kernel;

   protected override void Configure()
   {
      kernel = new StandardKernel();

      kernel.Bind<IWindowManager>().To<MetroWindowManager>().InSingletonScope();
      kernel.Bind<IEventAggregator>().To<EventAggregator>().InSingletonScope();

      kernel.Bind<IShellViewModel>().To<ShellViewModel>().InSingletonScope();
   }

   protected override void OnExit(object sender, EventArgs e)
   {
      kernel.Dispose();
      base.OnExit(sender, e);
   }

   protected override object GetInstance(Type service, string key)
   {
      if (service == null)
         throw new ArgumentNullException("service");
			
      return kernel.Get(service);
   }

   protected override IEnumerable<object> GetAllInstances(Type service)
   {
      return kernel.GetAll(service);
   }

   protected override void BuildUp(object instance)
   {
      kernel.Inject(instance);
   }
}