How do I get the current Castle Windsor container?
Asked Answered
P

2

14

I am a Castle Winsor Noob. I have a WebForm project that is a hot mess. I am trying to resolve a dependency to test user registration. How do I get to the current WindsorContainer?

IWindsorContainer container = ???;
IRegistrationLogic registrationLogic = container.Resolve<IRegistrationLogic>();
_registrationLogic.Register();

Here is my Bootstrapper:

public class WindsorConfigTask : ICastleBootstrapperTask
{

    public void Execute()
    {
        Container.AddFacility<WcfFacility>();
        Container.Register(
            Component.For<IProcessMessageRequest>()
                .ActAs(
                    new DefaultClientModel
                    {
                        Endpoint =
                            WcfEndpoint.ForContract<IProcessMessageRequest>().FromConfiguration("surveyClient2")
                    }
                ),
            Component.For<ILocalMembershipService>()
                .ActAs(
                    new DefaultClientModel
                    {
                        Endpoint =
                            WcfEndpoint.ForContract<ILocalMembershipService>().FromConfiguration(
                                "localMembershipClient")
                    })


            );

        Container.Register(Component.For<IRegistrationLogic>()
            .ImplementedBy<RegistrationLogic>()
            .LifeStyle.Is(LifeStyleType));
    }

    public IWindsorContainer Container { get; set; }


    #region ICastleBootstrapperTask Members


    public Castle.Core.LifestyleType LifeStyleType
    {
        get;
        set;
    }

    #endregion
}
Publicspirited answered 14/1, 2014 at 19:42 Comment(0)
D
9

There are many ways to solve this problem but I think the most common is to create a singleton helper class to hold the reference. Keep in mind you want to app to use DI to get everything from the container automatically. Perhaps only a few calls from the app will be to the container. Look at the controller factories for Windsor.

Something like this...

public static class ContainerManager
{
    public static IWindsorContainer Container = null;
}

Now I have been known to take it a step further and you could include some utilities with a get...

    public static class ContainerManager
    {
        private static IWindsorContainer _container = null;
        public static IWindsorContainer Container
        {
             get {
                 if (_container == null) {
                      // run installers, set _container = new container
                 }
                 return _container;
             }

        }
    }

I also realize you might be asking how do I get the container from a downstream dependent object... you can register the container with its self. By default it will register IKernel, but you can register IWindsorContainer for injection later. I would highly discourage using the container directly. As in you code above... do you do a Release when you are done???

Debauchee answered 14/1, 2014 at 19:54 Comment(0)
I
20

There is interface in Windsor for this purpose. It is called IContainerAccessor. Best place to implement it is the Global.asax file:

public class WebApplication : HttpApplication, IContainerAccessor {
  static IWindsorContainer container;

  public IWindsorContainer Container {
    get { return container; }
  }

  protected void Application_Start() {
    var bootstrapper = new WindsorConfigTask();
    bootstrapper.Execute();
    container = bootstrapper.Container; 
  }

  protected void Application_End() {
    container.Dispose();
  }
}

The usage in your web form is as following:

var containerAccessor = Context.ApplicationInstance as IContainerAccessor;
var container = containerAccessor.Container;
Indigoid answered 15/1, 2014 at 5:44 Comment(7)
That does the same thing I suggested but it is not obvious that you need to create a static of the container. The static is really the key, not the property the interface suggests.Debauchee
I does not, beacause here is well defined, when the container will be created and when it will be cleaned up. Your solution can bring some troubles.Angloindian
Thats great.. so how do I access this context in WebAPI?Shaylashaylah
You don't have to. WebAPI has extension points, where you can use container as a factory for your controllers. This solution is for WebForms and ASMX. They don't have this kind of extension points.Angloindian
I really like your answer. Upvoted. Just in case someone doesn't know how to do this in MVC, the var containerAccessor should be equal to HttpContext.Current.ApplicationInstance as IContainerAccessor;Doctrinaire
In MVC you have many interception points for much cleaner IoC container integration. See github.com/rarous/Castle.Windsor.Web.MvcAngloindian
For those wondering: WebApi has the same entry point as MVC: Global.asax, and you get it in the same way: HttpContext.Current.ApplicationInstance as IContainerAccessor. Thanks @YiannisP.Eratosthenes
D
9

There are many ways to solve this problem but I think the most common is to create a singleton helper class to hold the reference. Keep in mind you want to app to use DI to get everything from the container automatically. Perhaps only a few calls from the app will be to the container. Look at the controller factories for Windsor.

Something like this...

public static class ContainerManager
{
    public static IWindsorContainer Container = null;
}

Now I have been known to take it a step further and you could include some utilities with a get...

    public static class ContainerManager
    {
        private static IWindsorContainer _container = null;
        public static IWindsorContainer Container
        {
             get {
                 if (_container == null) {
                      // run installers, set _container = new container
                 }
                 return _container;
             }

        }
    }

I also realize you might be asking how do I get the container from a downstream dependent object... you can register the container with its self. By default it will register IKernel, but you can register IWindsorContainer for injection later. I would highly discourage using the container directly. As in you code above... do you do a Release when you are done???

Debauchee answered 14/1, 2014 at 19:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.