Earlier I asked this question. The answer to which resulted into another question like thou seeth before thee.
The initial problem
My problem is, that I have a custom MembershipProvider
using an AccountRepository
using an ObjectContext
. Because the MembershipProvider
is a Singleton
in MVC (as I understand), the AccountRepository
and its ObjectContext
should be injected once and stay there for the remainder of the MembershipProvider
's life time.
However, in my controllers I also use repositories with object contexts. In these controllers I need the object context to be shared between the repositories with a request. I have the following binding:
Bind<IMyContext>().To<MyObjectContext>().InRequestScope();
// put bindings here
Bind<IAccountRepository>().To<EFAccountRepository>
and in the Application_Start()
kernel.Inject(Membership.Provider);
The problem is that Ninject apparently calls dispose on the object context when it thinks the request is done (I think after 30 seconds).
My (not-working) solution
I noticed that when you set your bindings you can specify "when injecting into". The problem is, that I need "when injecting into when injecting into". I.e. when injecting the object context into the account controller when injecting the account controller into the membership provider. And I don't seem to have that...
Work-arounds I thought of (but don't really like).
- Don't hang
MyMembershipProvider
in MVC. Just pas an instance of it (behind and interface) to the controllers that need it like I do with repositories. Then Ninject will instantiate the provider per request. I don't like it because I'm sure MVC has a reason for instantiating the membership provider as a singleton. - Find an event that occurs every request and call
kernel.Inject
again in each event. Re-initializing the provider every request is nearly equivalent to re-instantiating, except dirtier. - Make a separate account repository for the membership provider to which I can bind in a different way. It doesn't seem right to change my object model because of Ninject.
Conclusion
IMHO the first work-around is the best. However, I much rather find a way to set Ninject to bind in the way I want.
What should I do?
The
.InRequestScope()
bit is causing some of your objects to be Disposed (see Cache and Collect).You need to make this (scoping by request) not happen in your provisioning of your provider's dependencies.
One way to achieve that is by having two bindings - one for the request processing branch and one for the global context, i.e., adding a
When
... which uses thecontext.ParentContext
... chain to control whether it'sInRequestScope()
or notSadly I don't have time to give a full answer now and the relevant docs are out of sync with the code at present.