3
votes

I have an interface ISession whose instance is produced by a different Session Factory depending on which namespace the class belongs to.

Example of my component registration:

IWindsorContainer container = new WindsorContainer();

container.Register(Component.For<NHibernate.ISession>()
  .UsingFactoryMethod((kernel, creationContext) =>
  {
    NHibernate.ISession session = 
      new SessionFactoryForNamespace1()
        .Instance.GetSession();

    return session;
  })
  .LifestylePerWebRequest());

container.Register(Component.For<NHibernate.ISession>()
  .UsingFactoryMethod((kernel, creationContext) =>
  {
    NHibernate.ISession session = 
      new SessionFactoryForNamespace2()
        .Instance.GetSession();

    return session;
  })
  .LifestylePerWebRequest());

container.Register(Component.For<Namespace1.IRepository1()
  .ImplementedBy<Namespace1.Repository1>());

container.Register(Component.For<Namespace2.IRepository2>()
  .ImplementedBy<Namespace2.Repository2>());

Example of the resolution graph:

public class MyController
{
    public MyController(Namespace1.IRepository1 repo1,
        Namespace2.IRepository2 repo2) { }
}

namespace Namespace1
{
    public interface IRepository1 { }
    public class Repository1 : IRepository1
    {
        public Repository1(NHibernate.ISession session) { }
    }
}

namespace Namespace2
{
    public interface IRepository2 { }
    public class Repository2 : IRepository2
    {
        public Repository2(NHibernate.ISession session) { }
    }
}

When Castle Windsor is asked to resolve MyController, it then tries to resolve IRepository1 and IRepository2, and subsequently the ISession for each. I want to have Castle Windsor select the component handlers based on the requestor type's namespace which in my example is either Namespace1 or Namespace2.

I am new to Castle Windsor and not sure where in the resolution pipeline I'm supposed to be plugging into.

What is the best approach to accomplish what I have outlined above?

2

2 Answers

4
votes

I think a service override would work for this.

UPDATE:

I also did an article on some of Windsor's advanced features (including a section on Service Overrides) that should augment the documentation linked above.

1
votes

Here is how I implemented service override solution:

Repository interfaces now inherit from a common repository interface:

public class MyController
{
    public MyController(Namespace1.IRepository1 repo1,
        Namespace2.IRepository2 repo2) { }
}

public interface IRepository { }

namespace Namespace1
{
    public interface IRepository1 : IRepository { }
    public class Repository1 : IRepository1
    {
        public Repository1(NHibernate.ISession session) { }
    }
}

namespace Namespace2
{
    public interface IRepository2 : IRepository { }
    public class Repository2 : IRepository2
    {
        public Repository2(NHibernate.ISession session) { }
    }
}

Repository component registeration based on its namespace:

IWindsorContainer container = new WindsorContainer();

...

Action<Type> RegisterRepository = t =>
{
    container.Register(
        AllTypes.FromAssemblyContaining(t)
            .BasedOn(typeof(IRepository))
            .WithServiceAllInterfaces()
            .Configure(c =>
            {
                c.DependsOn(
                    ServiceOverride
                        .ForKey<NHibernate.ISession>()
                        .Eq(c.Implementation.Namespace));

                c.LifeStyle.Is(LifestyleType.Transient);
            })
    );
};

RegisterRepository(typeof(Namespace1.IRepository1));
RegisterRepository(typeof(Namespace2.IRepository2));

Seems to work :)