Derik Whittaker

Syndication

News


Using Ninject (with CommonServiceLocator) with Caliburn.Micro on WP7

As I am in the process of rebuilding my Dimecasts.net WP7 application from the ground up to work with WP7 Mango one of the things I wanted to do was fully use the Caliburn.Micro framework.  Caliburn.Micro has its own built in IoC container called the PhoneContainer which provides basic Dependency Injection and this container works great but I have a bit of history using Ninject with my Wp7 applications so I wanted to replace the usage of the PhoneContainer with my Ninject, or more precisely the CommonServiceLocator implementation of Ninject.  I knew this had to be doable because there are examples of using MEF with Caliburn.Micro

Turns out I was right using Ninject w/ the CommonServiceLocator inside of Caliburn.Micro is doable and is very easy to boot.  Of course before I set out to build my own implementation of this I decided to google for it and this post was about the closest I could find to working code, but this code was NOT complete, at least for the current CM implementation.  Even though the post I found was not complete working code it was a great headstart in what needed to be done.

Here is how I got Caliburn.Micro to use Ninject as its IoC container.

Step 1: Register the setup bootstrapper that you want to use

You will need to open up your App.xaml file and put in the code below.

    <!--Application Resources-->
    <Application.Resources>
    	<local:NinjectBootstrapper x:Key="bootstrapper" />
    </Application.Resources>

Step 2: Create the a NinjectBootstrapper which inherits off of PhoneBootstrapper

Caliburn.Micor uses its bootstrapper to do some basic setup and configuration work.  It is here that we want to extend this and add support for Ninject and the CommonServiceLocator.  Go ahead and create a class as you see below.

public class NinjectBootstrapper : PhoneBootstrapper
{
    private NinjectContainer _ninjectContainer;

    protected override void Configure()
    {
        _ninjectContainer = new NinjectContainer(RootFrame);

        _ninjectContainer.RegisterDefaultBindings( typeof ( DashboardViewModel ), typeof ( IEventAggregator ) );
        _ninjectContainer.RegisterPhoneServices();

        var ninjectServiceLocator = new NinjectServiceLocator(_ninjectContainer.Kernel);

        ServiceLocator.SetLocatorProvider(() => ninjectServiceLocator);     
    }

    protected override object GetInstance(Type service, string key)
    {
        if (service != null)
        {
            return ServiceLocator.Current.GetInstance( service, key );
        }

        throw new ArgumentNullException("service");
    }

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

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

Step 3: Implement the Ninject Setup logic

As you can see from step 2 I have created a class which actually performs all the direct Ninject setup and I called it the NinjectContainer.  Below is the code for this container.  You should also note 2 more things:

  1. This container implements IPhoneContainer from Caliburn.Micro
  2. In the RegisterPhoneServices method this is a very manual rebinding of Caliburn.Micro and it is likely that I missed something.  This code was a direct port from the default implementation of the Caliburn IoC container setup.
public class NinjectContainer : IPhoneContainer
{
    private readonly IKernel _kernel;
    private readonly Frame _rootFrame;

    public NinjectContainer( Frame rootFrame )
    {
        _kernel = new StandardKernel();
        _rootFrame = rootFrame;
    }

    public event Action<object> Activated;

    public IKernel Kernel
    {
        get { return _kernel; }
    }

    public void RegisterWithPhoneService( Type service, string phoneStateKey, Type implementation )
    {}

    public void RegisterWithAppSettings( Type service, string appSettingsKey, Type implementation )
    {}

    public void RegisterPhoneServices(bool treatViewAsLoaded = false)
    {
        var phoneService = new PhoneApplicationServiceAdapter(_rootFrame);
        var navigationService = new FrameAdapter(_rootFrame, treatViewAsLoaded);
            
        Kernel.Rebind<IPhoneContainer>().ToMethod(x => this);
        Kernel.Rebind<INavigationService>().ToMethod(x => navigationService);
        Kernel.Rebind<IPhoneService>().ToMethod(x => phoneService);
        Kernel.Rebind<IEventAggregatorv().To<EventAggregator>().InSingletonScope();
        Kernel.Rebind<IWindowManager>().To<WindowManager>().InSingletonScope();
        Kernel.Rebind<IVibrateController>().To<SystemVibrateController>().InSingletonScope();
        Kernel.Rebind<ISoundEffectPlayer>().To<XnaSoundEffectPlayer>().InSingletonScope();
        Kernel.Rebind<StorageCoordinator>().To<StorageCoordinator>().InSingletonScope();
        Kernel.Rebind<TaskController>().To<TaskController>().InSingletonScope();
            

        var coordinator = Kernel.Get<StorageCoordinator>();
        coordinator.Start();

        var taskController = Kernel.Get<TaskController>();
        taskController.Start();
    }

    public void RegisterDefaultBindings( params Type[] typesToScanAssembliesFor )
    {
        // scan services
        Kernel.Scan(x =>
        {
            foreach ( var type in typesToScanAssembliesFor )
            {
                x.FromAssemblyContaining( type );
            }
                
            x.Where(type => type.Name.EndsWith("Service"));

            x.BindWithDefaultConventions();

            x.InSingletonScope();
        });

        // scan the rest
        Kernel.Scan(x =>
        {
            foreach (var type in typesToScanAssembliesFor)
            {
                x.FromAssemblyContaining(type);
            }

            x.Where(type => !type.Name.EndsWith("Service"));

            x.BindWithDefaultConventions();
        });
    }
}

Step 4: Hit F5 and see the fruits of your effort

Now if we did everything right your application should not be able to be run and Caliburn.Micro and Ninject (and CSL) as its IoC container.

As you can see you can swap out the built in IoC container w/ Ninject inside of Caliburn.Micro with almost no effort.  I hope this helps and others enjoy.

Till next time,


Posted 07-08-2011 4:35 AM by Derik Whittaker

[Advertisement]

Comments

dd wrote re: Using Ninject (with CommonServiceLocator) with Caliburn.Micro on WP7
on 08-16-2011 9:00 AM

dfsdfsdfds

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)