0
votes

I'm trying to register multiple named components for 2 different NHibernate sessions in my castle windsor container and depending on different interfaces (IRepository, IReadOnlyRepository) inject the appropriate NHibernate session.

I am using an AbstractFacility to register my ISession's and ISessionFactory's:

public class PersistenceFacility : AbstractFacility
{
    private const string DBCONNECTFACTORY = "dbconnectfactory";
    private const string ODSCONNECTFACTORY = "odsconnectfactory";
    private const string DBCONNECT = "dbconnect";
    private const string ODSCONNECT = "odsconnect";

    protected override void Init()
    {
        Kernel.Register(
            Component.For<ISessionFactory>()
                .UsingFactoryMethod(CreateDBConnectSessionFactory)
                .LifeStyle
                .Singleton
                .Named(DBCONNECTFACTORY),

            Component.For<ISessionFactory>()
                .UsingFactoryMethod(CreateODSConnectSessionFactory)
                .LifeStyle
                .Singleton
                .Named(ODSCONNECTFACTORY)
        );

        Kernel.Register(
            //Nhibernate session
            Component.For<ISession>()
                .UsingFactoryMethod(kernel => kernel.Resolve<ISessionFactory>(DBCONNECTFACTORY).OpenSession())
                .LifeStyle
                .PerWebRequest
                .Named(DBCONNECT),

            Component.For<ISession>()
                .UsingFactoryMethod(kernel => kernel.Resolve<ISessionFactory>(ODSCONNECTFACTORY).OpenSession())
                .LifeStyle
                .PerWebRequest
                .Named(ODSCONNECT)
        );
    }

    private static ISessionFactory CreateDBConnectSessionFactory()
    {
        return Fluently.Configure()
            .Database(NhOracleConfiguration.Dialect.ConnectionString(x => x.FromConnectionStringWithKey("DBConnect")))
            .Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetAssembly(typeof(StudentMapping))))
            .BuildSessionFactory();
    }

    private static ISessionFactory CreateODSConnectSessionFactory()
    {
        return Fluently.Configure()
            .Database(NhOracleConfiguration.Dialect.ConnectionString(x => x.FromConnectionStringWithKey("ODSConnect")))
            .Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetAssembly(typeof(ReadOnlyStudentMapping))))
            .BuildSessionFactory();
    }
}

The above works great for a single ISession, but I am in need of multiple now so that is my attempt.

I am registering my repositories as follows:

public void Install(IWindsorContainer container, IConfigurationStore store)
{
    container.Kernel.ComponentRegistered += Kernel_ComponentRegistered;

    container.AddFacility(new PersistenceFacility());

    // Register all controllers
    container.Register(
        // Unitofwork interceptor
        Component.For<NhUnitOfWorkInterceptor>().LifeStyle.PerWebRequest,

        // All validators
        Classes.FromAssembly(Assembly.GetAssembly(typeof(StudentValidator))).BasedOn(typeof(IValidator<>)).WithService.Base().LifestyleTransient(),

        // All repositories
        Classes.FromAssembly(Assembly.GetAssembly(typeof(NhStudentRepository)))
            .InSameNamespaceAs<NhStudentRepository>()
            .WithService.DefaultInterfaces()
            .LifestyleTransient(),

        // All services
        Classes.FromAssembly(Assembly.GetAssembly(typeof(StudentService))).InSameNamespaceAs<StudentService>().WithService.DefaultInterfaces().LifestyleTransient()

        );
}

The above code is registering all repositories (IRepository and IReadOnlyRepository) as they live in the same namespace.

How can I make sure the appropriate ISession is injected into the correct repository? (IRepository, IReadOnlyRepository)

Am I even going in the right direction with my approach? I'm certainly open to completely reworking how I am registering components and dependencies.

2

2 Answers

2
votes

I tried your code with the following configuration ;

  public class Repository<T>:IRepository<T> where T:class 
  {


    public T GetById(string id)
    {

        return UnitOfWork.CurrentDBSession.Get<T>(id);

    }   


    }

with

public class UnitOfWork
{
      public static ISession CurrentDBSession
        {
            get
            {
                var session = IoC.Container.Resolve<ISession>("dbconnect");
                return session;
            }
        }
}

and it worked well.This may help you If i understood your problem correctly.

1
votes

I solved this issue by using a ServiceOverride when registering my two different repository classes (IRepository, IReadOnlyRepository).

I'd be curious to see a more updated solution as ServiceOverride seems to be deprecated after Castle Windsor 3.0.

The key to my implementation is to have my different repositories live in different namespaces, and let Castle Windsor register each with a different named ISession component:

public void Install(IWindsorContainer container, IConfigurationStore store)
{
    container.Kernel.ComponentRegistered += Kernel_ComponentRegistered;

    container.AddFacility(new PersistenceFacility());

    // Register all controllers
    container.Register(
        // Unitofwork interceptor
        Component.For<NhUnitOfWorkInterceptor>().LifeStyle.PerWebRequest,

        // All validators
        Classes.FromAssembly(Assembly.GetAssembly(typeof(StudentValidator))).BasedOn(typeof(IValidator<>)).WithService.Base().LifestyleTransient(),

        // All repositories
        Classes.FromAssembly(Assembly.GetAssembly(typeof(NhStudentRepository)))
            .InSameNamespaceAs<NhStudentRepository>()
            .WithService.DefaultInterfaces()
            .Configure(c =>
            {
                c.DependsOn(
                    ServiceOverride
                        .ForKey<ISession>()
                        .Eq(DBCONNECT)
                    );
            })
            .LifestyleTransient(),

        // All read only repositories
        Classes.FromAssembly(Assembly.GetAssembly(typeof(NhCourseRepository)))
            .InSameNamespaceAs<NhCourseRepository>()
            .WithService.DefaultInterfaces()
            .Configure(c => 
                {
                    c.DependsOn(
                        ServiceOverride
                            .ForKey<ISession>()
                            .Eq(ODSCONNECT)
                        );
                })
            .LifestyleTransient(),

        // All services
        Classes.FromAssembly(Assembly.GetAssembly(typeof(StudentService))).InSameNamespaceAs<StudentService>().WithService.DefaultInterfaces().LifestyleTransient()

        );
}