views:

29

answers:

1

I am using CommonSrviceLocator with WindworContainer for resolving my NHibernage.ISession instances. ISession instances is created through SessionFactory. For some reason I need to work with different databases in one application, so I need different connection strings and different NHibernate.ISession objects.

SessionFactory can create different ISession objects by DB name. So I want to get different ISession objects in my application using following syntax:

ISesssion sessionForDb1 = ServiceLocator.Current.GetInstance<ISession>("session-for-db1");
ISesssion sessionForDb2 = ServiceLocator.Current.GetInstance<ISession>("session-for-db2");

To achieve that I've created following container registrations:

IWindsorContainer container = new WindsorContainer();
container.AddFacility<FactorySupportFacility>();

container.Register(
    Component.For<ISessionFactory>()
        .Named("session-factory-for-db1")
        .LifeStyle.Singleton
        .UsingFactoryMethod(() => new NHibernateConfigurator().CreateSessionFactoryForDb1()),

    Component.For<ISessionFactory>()
        .Named("session-factory2-for-db2")
        .LifeStyle.Singleton
        .UsingFactoryMethod(() => new NHibernateConfigurator().CreateSessionFactoryForDb2()),

    Component.For<ISession>()
        .Named("session-for-db1")
        .LifeStyle.PerWebRequest
        .UsingFactoryMethod(kernel => kernel.Resolve<ISessionFactory>("session-factory-for-db1").OpenSession()),

    Component.For<ISession>()
        .Named("session-for-db2")
        .LifeStyle.PerWebRequest
        .UsingFactoryMethod(kernel => kernel.Resolve<ISessionFactory>("session-factory2-for-db2").OpenSession())
        );

 ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(container));

This works, but the thing I don't like here is that I need to create a lot of string constants that represents families of objects and build each with the other naming each instance. So for this task I need to register 4 string constants, if my SessionFactory must be created with another factory I will probably need to define 6 constants, etc.

I would like to know if there is any better approach for registering similar families of objects?

+1  A: 

When there are multiple services with the same service type, you have to use the component id (string) to discriminate them. In your case, if you never inject any ISessionFactory directly into your classes, you could wrap this registration in an extension method, e.g.:

public static class WindsorSessionFactoryExtensions {
    public static void RegisterSession(this IWindsorContainer container, string name, Func<NHibernateConfigurator, ISessionFactory> configurator) {
        var id = Guid.NewGuid().ToString();
        container.Register(
            Component.For<ISessionFactory>()
                .Named(id)
                .LifeStyle.Singleton
                .UsingFactoryMethod(() => configurator(new NHibernateConfigurator())),
            Component.For<ISession>()
                .Named(name)
                .LifeStyle.PerWebRequest
                .UsingFactoryMethod(k => k.Resolve<ISessionFactory>(id).OpenSession())
            );
    }
}

container.RegisterSession("session-for-db1", c => c.CreateSessionFactoryForDb1());
container.RegisterSession("session-for-db2", c => c.CreateSessionFactoryForDb2());
var session = container.Resolve<ISession>("session-for-db1");

Or instead of using a GUID for the session factory id, you could do something like var id = name + "-factory" kind of thing, like a convention.

Another possibility would be using ExtendedProperties, but that could complicate things even more and in the end there always has to be some sort of discriminator.

But the real problem here is that you're using the service locator. In normal container usage you should never have to use it. Instead, use service overrides to define what session you want in your registered components.

Mauricio Scheffer
Thank you very much, can you describe you opinion about service locator in a little more words. Why I don't have to use it? And how Service override applies in this situation?
Restuta
re service locator, see http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx
Mauricio Scheffer
re service overrides: see http://stw.castleproject.org/Windsor.Registering-components-one-by-one.ashx#Supplying_the_component_for_a_dependency_to_use_Service_override_9 http://blog.bittercoder.com/PermaLink,guid,6c1a25f7-5c8c-4a5e-bda9-04ffa944ebd0.aspx
Mauricio Scheffer