在Windsor Container中为同一类型注册多个实例的正确方法是什么?

时间:2010-07-28 08:54:29

标签: .net castle-windsor ioc-container

我正在使用 CommonSrviceLocator WindworContainer 来解析我的 NHibernage.ISession 实例。 ISession 实例是通过 SessionFactory 创建的。出于某种原因,我需要在一个应用程序中使用不同的数据库,因此我需要不同的连接字符串和不同的 NHibernate.ISession 对象。

SessionFactory 可以按数据库名称创建不同的 ISession 对象。所以我希望使用以下语法在我的应用程序中获得不同的 ISession 对象:

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

为了实现这一点,我创建了以下容器注册:

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));

这是有效的,但我不喜欢的是我需要创建很多表示对象族的字符串常量,并使用另一个命名每个实例来构建每个对象。所以对于这个任务,我需要注册4个字符串常量,如果我的 SessionFactory 必须用另一个工厂创建,我可能需要定义6个常量等。

我想知道是否有更好的方法来注册类似的对象系列?

1 个答案:

答案 0 :(得分:1)

当存在多个具有相同服务类型的服务时,您必须使用组件ID(字符串)来区分它们。在您的情况下,如果您从未将任何ISessionFactory直接注入到类中,则可以将此注册包装在扩展方法中,例如:

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");

或者不是使用GUID作为会话工厂ID,而是可以执行类似var id = name + "-factory"之类的事情,例如约定。

另一种可能性是使用ExtendedProperties,但这可能会使事情变得更复杂,最终总会有某种鉴别器。

但这里真正的问题是你正在使用服务定位器。在正常的容器使用中,您永远不必使用它。而是使用服务覆盖来定义所需的注册组件会话。