MVC 3 ninject custom membership context disposed error

前端 未结 1 869
滥情空心
滥情空心 2021-01-26 21:30

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

1条回答
  •  礼貌的吻别
    2021-01-26 22:26

    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:

    1. Bind the CustomerService as InSingletonScope along with the membership provider itself. Obviously, this has all of the usual drawbacks of long-lived EF services.

    2. 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.

    0 讨论(0)
提交回复
热议问题