Windsor Bootstrapper

Oct 14, 2010 at 12:12 PM

Like the Ninject Bootstrapper discussion.. here is my implementation for a Castle.Windsor Boostrapper (should work with Castle.Windsor 2.5 too).

WindsorContainerFactory does nothing more then creating a WindsorContainer and install FactorySupport.


namespace UI.Shell.Infastructure
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using Caliburn.Micro;
    using Castle.Core;
    using Castle.MicroKernel.Registration;
    using Castle.Windsor;     

    public class AppBootstrapper : Bootstrapper<IShell>
    {
        private IWindsorContainer _windsorContainer;

        protected override void Configure()
        {
            _windsorContainer = WindsorContainerFactory.Create();
            _windsorContainer.Install(new CommonsWindsorInstaller(),
                                      new InfastructureInstaller(),
                                      new CaliburnMicroInstaller(),
                                      new ViewModelInstaller(),
                                      new MessageHandlerInstaller());

            //Shell
            _windsorContainer.Register(
                Component.For<IShell>()
                    .ImplementedBy<ShellViewModel>()
                    .LifeStyle.Is(LifestyleType.Singleton));

            var eventAggregator = _windsorContainer.Resolve<IEventAggregator>();

            var messageHandlers = _windsorContainer.ResolveAll<IMessageHandler>();
            foreach (var messageHandler in messageHandlers)
            {
                eventAggregator.Subscribe(messageHandler);    
            }
        }

        protected override IEnumerable<Assembly> SelectAssemblies()
        {
            return AppDomain.CurrentDomain.GetAssemblies();
        }

        protected override object GetInstance(Type service, string key)
        {
            return string.IsNullOrWhiteSpace(key) ? _windsorContainer.Resolve(service) : _windsorContainer.Resolve(key, new { });
        }

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

        protected override void BuildUp(object instance)
        {
            instance.GetType().GetProperties()
                .Where(property => property.CanWrite && property.PropertyType.IsPublic)
                .Where(property => _windsorContainer.Kernel.HasComponent(property.PropertyType))
                .ForEach(property => property.SetValue(instance, _windsorContainer.Resolve(property.PropertyType), null));
        }
    }
}
Nov 9, 2010 at 8:40 AM

This example doesn't work with the current Castle version...

Nov 9, 2010 at 8:53 AM

Could you provide more information? Whats the problem?

Nov 9, 2010 at 9:13 PM
Edited Nov 9, 2010 at 9:14 PM

Sorry for that unqualified post. For an example, the above code is a little bit hard to copy into another project. There's no WindsorContainerFactory, nor any installers as mentioned. So I tried it with

protected override void Configure()
{
_windsorContainer = new WindsorContainer(); _windsorContainer.Register(Component.For<IWindsorContainer>().Instance(_windsorContainer)); 
_windsorContainer.Register(Component.For<IWindowManager>().ImplementedBy<WindowManager>()); 
_windsorContainer.Register(Component.For<IEventAggregator>().ImplementedBy<EventAggregator>());  

_windsorContainer.Register(Component.For<IShell>().ImplementedBy<ShellViewModel>().LifeStyle.Is(LifestyleType.Singleton)); 
}

for the WPF part, where AppDomain.CurrentDomain.GetAssemblies is available. Now I get a TargetInvokationException, when it tries to resolve "ShellView".

Oh, funny, with SL I now get not the same error as before (BuildUp and SelectAssemblies are here outcommented). Now I get MethodAccessException, something with ReflectionBasedDictionaryAdapter.

Nov 9, 2010 at 9:47 PM

Changing GetAllInstances into

protected override IEnumerable<object> GetAllInstances(Type service)
{
  return _windsorContainer.ResolveAll<object>().Where(c=>c.GetType()==service);
}

and it works as good as the LightCore example...
Nov 9, 2010 at 10:52 PM

Much better:

 protected override IEnumerable<object> GetAllInstances(Type service)
{
      return _windsorContainer.ResolveAll(service).Cast<object>();
}
Nov 10, 2010 at 7:12 AM

Thxs for your suggestions. I've redone the Bootstrapper like this:

You do not need to register the container itself because Castle provides IKernel injections out of the box.

 

public class AppBootstrapper : Bootstrapper<IShell>
    {
        private IWindsorContainer _windsorContainer;

        protected override void Configure()
        {
            _windsorContainer = new WindsorContainer();
            _windsorContainer.Register(Component.For<IWindowManager>().ImplementedBy<WindowManager>()); 
            _windsorContainer.Register(Component.For<IEventAggregator>().ImplementedBy<EventAggregator>());  

           
            //Shell
            _windsorContainer.Register(
                Component.For<IShell>()
                    .ImplementedBy<ShellViewModel>()
                    .LifeStyle.Is(LifestyleType.Singleton));

            var eventAggregator = _windsorContainer.Resolve<IEventAggregator>();

            var messageHandlers = _windsorContainer.ResolveAll<IMessageHandler>();
            foreach (var messageHandler in messageHandlers)
            {
                eventAggregator.Subscribe(messageHandler);    
            }
        }

        protected override IEnumerable<Assembly> SelectAssemblies()
        {
            return AppDomain.CurrentDomain.GetAssemblies();
        }

        protected override object GetInstance(Type service, string key)
        {
            return string.IsNullOrWhiteSpace(key) ? _windsorContainer.Resolve(service) : _windsorContainer.Resolve(key, new { });
        }

        protected override IEnumerable<object> GetAllInstances(Type service)
        {
            return _windsorContainer.ResolveAll(service).Cast<object>();
        }

        protected override void BuildUp(object instance)
        {
            instance.GetType().GetProperties()
                .Where(property => property.CanWrite && property.PropertyType.IsPublic)
                .Where(property => _windsorContainer.Kernel.HasComponent(property.PropertyType))
                .ForEach(property => property.SetValue(instance, _windsorContainer.Resolve(property.PropertyType), null));
        }
    }


 

Nov 29, 2010 at 5:03 PM

Hi there;

I was trying to get the Windsor as the container for a sample I was doing with CM. The above discussions was very valuable. The issue I was facing now is the BuildUp() method is never called. I tried to run by having a break point at the BuildUp() method and never reached there.  I am getting an exception saying "No component for key {ViewModelName} was found. I assume this is due to the fact that the container didnt have the object created correctly. Any thoughts on getting this resolved.

Thanks much for the help.

SKR