简体   繁体   中英

Castle Windsor “Late bound” components

I've got several components registered in my container and Windsor can inject them without problems. Now I've added a new registration for NHibernate ISessionFactory in this way:

foreach (KeyValuePair<string, string> _tenantItem in _contextWrapper.TenantsConnectionStrings)
        {
            var config = Fluently.Configure()
                .Database(
                    MsSqlConfiguration.MsSql2008
                    .UseOuterJoin()
                    .ConnectionString(_tenantItem.Value)
                    .FormatSql()
                    .ShowSql()
                )

                .ExposeConfiguration(ConfigurePersistence)
                .ProxyFactoryFactory(typeof(ProxyFactoryFactory))
                .BuildConfiguration();

            Kernel.Register(
                Component.For<ISessionFactory>()
                    .UsingFactoryMethod(config.BuildSessionFactory)
                    .Named(_tenantItem.Key)
                    .LifestyleTransient()
                    );
        }

Now if I try to inspect my container I see:

在此处输入图片说明

Component Implementation is "Late bound" and Windsor won't inject it.

What's wrong? What I can check?

There are two separate and unrelated questions here so let me answer them in turn.

"late bound" as the component description says, merely means Windsor doesn't know the implementation type of your ISessionFactory statically. This is not a reason for concern.

It's simply up to the factory method you specify, config.BuildSessionFactory() in your case, to build the instance and it may not even be the same type every time.

One might implement the factory method like:

public ISessionFactory BuildSessionFactory()
{
   if (Today == DayOfWeek.Friday)
   {
      return new BeerOClockSessionFactory();
   }
   return SomeOtherSessionFactory();
}

This is fine and normal.

The other question you hinted at, indicates that you may be experiencing unexpected behaviour where the dependency on the ISessionFactory is not satisfied as expected.

Sadly, unless you explain more about it, share what sort of errors you're seeing I don't think there's much I can help other than to say "it should be working".

Also while we're at it, I wholeheartedly agree with @raulg that making session factory transient doesn't sound like a particularly good idea.

It probably doesn't like that you are creating your config instance at runtime.

You would be better off creating a proper class for your config, registering it with the container, and using that to create ISessionFactory instance.

public class MySessionFactoryBuilder : IMySessionFactoryBuilder
{
    private FluentConfiguration _fluentConfiguration = null;

    public MySessionFactoryBuilder()
    {
    }

    void Initialize(string connectionStringKey)
    {
        IPersistenceConfigurer persistenceConfigurer = null;

        persistenceConfigurer = MsSqlConfiguration.MsSql2008
                .UseOuterJoin()
                .ConnectionString(connectionStringKey)
                .FormatSql()
                .ShowSql()
                ;

        _fluentConfiguration = Fluently.Configure()
            .Database(persistenceConfigurer)
            .ExposeConfiguration(ConfigurePersistence)
            .ProxyFactoryFactory(typeof(ProxyFactoryFactory))
            .BuildConfiguration()
            ;
    }

    public ISessionFactory BuildSessionFactory(string connectionStringKey)
    {
        Initialize(connectionStringKey);
        return _fluentConfiguration.BuildSessionFactory();
    }

}

You can have that registered normally. Then you register multiple ISessionFactory, one per tenant, in your installer loop:

foreach (KeyValuePair<string, string> _tenantItem in _contextWrapper.TenantsConnectionStrings)
{

    container.Register(
    Component.For<ISessionFactory>()
        .UsingFactoryMethod(k => k.Resolve<MySessionFactoryBuilder>().BuildSessionFactory(_tenantItem.Value))
        .Named(_tenantItem.Key),

    Component.For<ISession>()
        .UsingFactoryMethod(k => k.Resolve<ISessionFactory>().OpenSession())
        .Named(_tenantItem.Key + "-nhsession")
        .LifeStyle.Transient
        );

}

Note, i registered ISession transient, but not ISessionFactory. Normally you want to keep your ISessionFactory as long as possible, as it is expensive to create.

I haven't tested it, but i'm guessing that will resolve it, as the implementation of the session factory builder is known at compile-time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM