Hierarchical Containers
This is somewhat of a specific scenario, but let us assume that you have an application where you want to specialize the services of the applications by the current user. If the user belongs to the Northwind customer, you want to have one behavior, and if it belongs to the Southsand customer, you want to have a different behavior. All users from all others customers get the default behavior.
To make it simple, let us talk about NHibernate configuration. You have a default schema that you use for most customers, and you specialize that for those customers that wants extra. This means that you need to keep a session factory per customer, because you have different schema that in the default one (changing the connection string is not enough).
To be clear, this is not about entity inheritance, this is about specialization of the entire application, which I just happened to demonstrate via NH configuration.
Now, Windsor supports this ability by having a parent container and child containers, but Binsor didn't expose this functionality easily, I did some work on it today, and the end result is that you can configure it like this:
We have the global container (implicit to Binsor, since we created it before we run the Binsor script), then we run over the configuration files and create a container per each file. We register them in the ContainerSelector, which is an application level service (below).
import HierarchicalContainers import System.IO Component("nhibernate_unit_of_work", IUnitOfWorkFactory, NHibernateUnitOfWorkFactory, configurationFileName: """..\..\hibernate.cfg.xml""") Component("nhibernate_repository", IRepository, NHRepository) Component("container_selector", ContainerSelector) for configFile in Directory.GetFiles("""..\..\Configurations""", "*.cfg.xml"): continue if Path.GetFileName(configFile) == "hibernate.cfg.xml" print "Build child configuration for ${configFile}" child = RhinoContainer(IoC.Container) using IoC.UseLocalContainer(child): Component("nhibernate_unit_of_work", IUnitOfWorkFactory, NHibernateUnitOfWorkFactory, configurationFileName: configFile) Component("nhibernate_repository", IRepository, NHRepository) #need to remove both .cfg and .xml containerName = Path.GetFileNameWithoutExtension(Path.GetFileNameWithoutExtension(configFile)) IoC.Container.Resolve(ContainerSelector).Register(containerName, child)
You can use it like this, and enter/leave the context of the a client at will:
RhinoContainer container = new RhinoContainer("Windsor.boo"); IoC.Initialize(container); ContainerSelector containerSelector = IoC.Resolve<ContainerSelector>(); containerSelector.PrintChildContainers(); using(UnitOfWork.Start()) { Console.WriteLine( NHibernateUnitOfWorkFactory.CurrentNHibernateSession .Connection.ConnectionString ); } using(containerSelector.Enter("Northwind")) { using (UnitOfWork.Start()) { Console.WriteLine( NHibernateUnitOfWorkFactory.CurrentNHibernateSession .Connection.ConnectionString ); } } using (containerSelector.Enter("Southsand")) { using (UnitOfWork.Start()) { Console.WriteLine( NHibernateUnitOfWorkFactory.CurrentNHibernateSession .Connection.ConnectionString ); } }
Because this is a fairly complex topic, I have created a simple reference implementation that you can get here:
https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/SampleApplications/HierarchicalContainers
Comments
I love the using selector syntax. I posted a patch a while ago that allows you to configure child containers and name them using the standard XmlInterpreter. The selector will be a nice addition.
Thanks man, that's great!!!
Comment preview