The factory was disposed and can no longer be used. NHibernatefacility
Asked Answered
B

1

6

I have been trying for three days to figure out this NHibernatefacility thing with Castle and wcf and it's really getting frustrating.

After solving a good dozen of errors, i have come to this one which seems pretty obvious but i can't solve.

This is my global.asax's Application_Start

        container.AddFacility<AutoTxFacility>();
        container.Register(Component.For<INHibernateInstaller>().ImplementedBy<NHibernateInstaller>());
        container.AddFacility<NHibernateFacility>();
        container.AddFacility<WcfFacility>();

        container.Register(
            Component.For<IAuthService>().ImplementedBy<AuthService>().LifestylePerWcfOperation(),
            Component.For<IUserRepository>().ImplementedBy<UserRepository>().LifestylePerWcfOperation(),
            Component.For<IActionWebService>().ImplementedBy<ActionWebService>().Named("ActionWebService").LifestylePerWcfOperation(),
            Component.For<ISession>().LifeStyle.PerWcfOperation().UsingFactoryMethod(x => container.Resolve<ISessionManager>().OpenSession()));

This works for the first request. After that, it comes up with this error.

The factory was disposed and can no longer be used. Object name: 'this'.

the error is happening in my userrepository in this line

[Transaction]
        public virtual User GetUserByCredentials(string email, string password)
        {
            using (var tx = session())
            {
                return tx.QueryOver<User>().Where(x => x.Email == email && x.Password == password).SingleOrDefault();
            }
        }

I am having a feeling this has to do with the LIfestyle. I have tried multiple combinations but unsuccessful. I don't know what to do at this point. I got into this Castle thing with all the facilities (that are supposed to make life easier) and it's really complicated due to the lack of documentation. I haven't been able to find a descent guide to implement all of this together, not to mention something that is not 4 years old.

Help Please!

Brier answered 28/11, 2012 at 18:11 Comment(3)
Can you post more repository code? I'm unsure why you have a session method (shouldn't your session be injected by castle?). Seeing the dispose method on your repository would be useful as well if it is in fact a lifestyle issue.Levitt
Hello Andrew. I am just following the documentation. session is a Func<ISession> and it's injected into the repository in the constructor. Look at the global.asax. I managed to solve this setting the lifestyle for the Isession to Singleton. I don't know if it is the right thing to do, but at least is working now.Brier
Has anybody crossing this post had the same issues? I am back to problems again :(Brier
E
1

Sorry for not finding this question previously.

The most likely reason you're getting this error message is that you are re-registering the ISession. The point of the facility is to provide that support for you.

I also read in your comment that you have set the ISession to singleton. That should never ever be done, because any single fault on it an you will crash and burn and you'll have to throw away the full container (which most often is the composition root of the application, so you have to reboot the application).

The point of the facility is to give you AOP-based transactions, and then you need to have your transactions as close to the GUI or command layer as possible. Child operation, such as reading should not be wrapped in singular transactions with [Transaction] because they do not denote the transactional boundary for your operation.

Instead, look at your surface API and see where you have methods being called that are supposed to run with ACID; this is where you put the attributes.


In your case, it seems that your transactional boundaries are around the WCF calls. What you'd need to do is to replace the lifestyle that the ISession is registered with.

If you have a look at the c'tor for NHibernateFacility, you'll find an option to pass transient lifestyle; if all of your components depending on ISession are transient you'll be good to go with Transient lifestyle on ISession, because it is guaranteed to only live for as long as the object taken from the composition root/container lives.

The 'real' fix is to extend the facility, from my github, with an enum in the c'tor taking a PerWCFOperation value, and having the facility register ISessionManager and Func with those, similar to how it does with the three existing lifestyles.

Extended answered 28/12, 2012 at 20:32 Comment(4)
Hello Henrik. I sent to your email a "copy" of my project and how i am implementing your facilities. Let me know when you check it out so we can post here a solution to the other folks. Thank you so much.Brier
To be truly honest, your last paragraph put a "puzzle face" on my face.... Sometimes i can't understand how i can understand some programming concepts so clearly, and others, that don't seem to complicated, simply become impossible for me to figure out.Brier
Hi, I haven't had time to look through your code yet. We're talking lifestyles of objects here. Check that for a given object that needs a transaction, all things it depends on are transients and make sure you resolve and release it as a part of the cross-cutting concern of the WCF operation. That's what PerWCFOperation does, but if you open a transaction inside a WCF operation, then that transaction will have its resolved items disposed before your WCF operation ends and then you will get your error message.Extended
Hello Henrik. I understand. Any help will be highly appreciate it. I found this article. Do you think this could be of any help? A starting point? My only concern with most of this articles is that they are old. richarddingwall.name/2010/08/17/… let me know what you think of this one. ThanksBrier

© 2022 - 2024 — McMap. All rights reserved.