I have a custom membership that uses my CustomerService to communicate with the database using EF code first (4.1) I use ninject to inject the CustomerService into my custom mem
This is a common mistake for people who are starting out with DI and IoC containers. You have to maintain consistency of scopes. You cannot have dependencies bound to a request scope when the services that depend on them are bound to singleton scope (or worse, have some scope not managed by the container at all). It's simply wrong.
You have two basic options here:
Bind the CustomerService
as InSingletonScope
along with the membership provider itself. Obviously, this has all of the usual drawbacks of long-lived EF services.
Don't have your membership provider depend on the CustomerService
instance. Instead, make the dependency on a CustomerServiceFactory
which can create CustomerService
instances, and treat every call to the membership provider as transient.
For #2, the process of creating and binding a factory is very simple:
public interface ICustomerServiceFactory
{
ICustomerService GetService();
}
public class NinjectCustomerServiceFactory : ICustomerServiceFactory
{
private readonly IKernel kernel;
public NinjectCustomerServiceFactory(IKernel kernel)
{
if (kernel == null)
throw new ArgumentNullException("kernel");
this.kernel = kernel;
}
public ICustomerService GetService()
{
return kernel.Get();
}
}
Then in your module:
Bind()
.To();
.InRequestScope();
Bind()
.To()
.InSingletonScope();
Note the scopes here. The service itself is still request-scoped, but the factory is singleton, which is the same scope as the provider. This works because the factory goes directly to the kernel, which is also singleton (more or less).
You'd end up with membership code looking like so:
public class MyMembershipProvider : MembershipProvider
{
public override MembershipUserCollection GetAllUsers()
{
var service = serviceFactory.GetService();
var serviceUsers = service.GetAllUsers();
return serviceUsers.Select(u => CreateMembershipUser(u));
}
// Other methods...
[Inject]
public ICustomerServiceFactory ServiceFactory { get; set; }
}
This actually works very well because the service itself will still be request-scoped, but the factory (and thus the membership provider) will just get a different instance during each request. Not only that but the membership provider is guaranteed to get the same instance (through the factory) no matter how many membership methods are called during a single request. So you're getting almost all the benefits of DI, in spite of having to integrate into legacy code.