Castle Windsor, Fluent Nhibernate, and Automapping

2019-07-03 22:55发布

问题:

I'm new to the whole castle Windsor, Nhibernate, Fluent and Automapping stack so excuse my ignorance here. I didn't want to post another question on this as it seems there are already a huge number of questions that try to get a solution the Windsor nhib Isession management problem, but none of them have solved my problem so far. I am still getting a ISession is closed exception when I'm trying to call to the Db from my Repositories,Here is my container setup code.

container.AddFacility<FactorySupportFacility>()
            .Register(
                Component.For<ISessionFactory>()
                    .LifeStyle.Singleton
                    .UsingFactoryMethod(() => Fluently.Configure()
                                                  .Database(
                                                      MsSqlConfiguration.MsSql2005.
                                                          ConnectionString(
                                                              c => c.Database("DbSchema").Server("Server").Username("UserName").Password("password")))
                                                  .Mappings
                                                     (
                                                      m => 
                                                      m.AutoMappings.Add
                                                        (
                                                          AutoMap.AssemblyOf<Message>(cfg)
                                                          .Override<Client>(map =>
                                                          {
                                                              map.HasManyToMany(x => x.SICCodes).Table("SICRefDataToClient");
                                                          })
                                                          .IgnoreBase<BaseEntity>()
                                                          .Conventions.Add(DefaultCascade.SaveUpdate())
                                                          .Conventions.Add(new StringColumnLengthConvention(),new EnumConvention())
                                                          .Conventions.Add(new EnumConvention())

                                                          .Conventions.Add(DefaultLazy.Never())
                                                        )
                                                      )
                                                  .ExposeConfiguration(ConfigureValidator)
                                                  .ExposeConfiguration(BuildDatabase)
                                                  .BuildSessionFactory() as SessionFactoryImpl),
                 Component.For<ISession>().LifeStyle.PerWebRequest.UsingFactoryMethod(kernel => kernel.Resolve<ISessionFactory>().OpenSession()
                                                  ));

In my repositories i inject private readonly ISession session; and use it as followes

 public User GetUser(int id)
    {
        User u;

            u = session.Get<User>(id);
            if (u != null && u.Id > 0)
            { 
                NHibernateUtil.Initialize(u.UserDocuments);
            }


        return u;

in my web.config inside <httpModules>. i have also added this line

      <add name="PerRequestLifestyle" 
type="Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule, Castle.Windsor"/>

I'm i still missing part of the puzzle here, i can't believe that this is such a complex thing to configure for a basic need of any web application development with nHibernate and castle Windsor.

I have been trying to follow the code here windsor-nhibernate-isession-mvc and i posted my question there as they seemed to have the exact same issue but mine is not resolved.

UPDATE MooKid8000 i have now updated my castle register code to this

private void AddRepositories()
    {
        container.Register(
            AllTypes.FromAssembly(typeof(MembershipRepository).Assembly)
                .Pick()
                .Configure(c => c.Interceptors(
                    InterceptorReference.ForKey("simpleLogger")).Anywhere
                )
                .Configure(c => c.LifeStyle.Is(LifestyleType.Transient))
                .WithService.FirstInterface());
    }

But I'm still getting the ISession is closed issue, Do my services need to be registered as Transient as well, Can you explain in more detail why they should be transient and not singleton's

UPDATE MooKid8000 suggestion was 100% correct , I just need to make sure my services and repositories where all scoped as LifestyleType.Transient so the ISession wasn't wiped out. Great spot Mookid8000 without even seeing my castle registration code initially.

For anybody that is intrested contact me and i can send you my container setup.

回答1:

Did you remember to register your repositories with a transient lifestyle?

If your repositories are singletons (which is the default lifestyle with Windsor), then the injected ISession instance will be "caught", resulting in closed session errors later on.

Note that any services using your repositories must also have a transient lifestyle, as well as any services using those services, and so on.

Generally, you could say that the lifestyle granularity should not increase as you go further away from the composition root, otherwise some kind of scoping will happen. Of course this is not always a problem, but it can lead to errors that are pretty hard to diagnose.