MVC 3 ninject自定义成员资格上下文错误

时间:2011-09-05 07:33:40

标签: asp.net-mvc ninject membership

我有一个自定义成员资格,它使用我的CustomerService首先使用EF代码与数据库进行通信(4.1) 我使用ninject将CustomerService注入我的自定义成员资格类。 但是当我尝试验证时,我得到一个上下文处理错误。 这是因为在我的上下文中,存储库和服务是InRequestScope()。 因为我使用[inject]在我的自定义成员资格的属性上注入CustomerService,而在ninject中使用_kernel.Inject(Membership.Provider),它只在启动时注入了。

我阅读了很多有关此问题的帖子,但无法找到解决此问题的答案。

有没有人有解决方案?

1 个答案:

答案 0 :(得分:9)

对于刚开始使用DI和IoC容器的人来说,这是一个常见的错误。您必须保持范围的一致性。当依赖于它们的服务绑定到单一范围时,不能将依赖关系绑定到请求范围(或者更糟糕的是,某些范围根本不由容器管理)。这完全是错的。

这里有两个基本选项:

  1. CustomerServiceInSingletonScope绑定为会员提供商本身。显然,这具有长期EF服务的所有常见缺点。

  2. 不要让您的会员提供者依赖于CustomerService实例。相反,依赖于CustomerServiceFactory可以创建 CustomerService个实例,并将对会员提供商的每次调用都视为瞬态。

  3. 对于#2,创建和绑定工厂的过程非常简单:

    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<ICustomerService>();
        }
    }
    

    然后在你的模块中:

    Bind<ICustomerService>()
        .To<EFCustomerService>();
        .InRequestScope();
    Bind<ICustomerServiceFactory>()
        .To<NinjectCustomerServiceFactory>()
        .InSingletonScope();
    

    请注意此处的范围。服务本身仍然是请求范围的,但工厂是单例,与提供者的范围相同。这是有效的,因为工厂直接进入内核,这也是单例(或多或少)。

    您的会员资格代码最终会如此:

    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; }
    }
    

    这实际上非常有效,因为服务本身仍然是请求范围的,但工厂(以及成员资格提供者)将在每个请求期间获得不同的实例。不仅如此,无论在单个请求期间调用多少成员资格方法,成员资格提供者都可以保证获得相同的实例(通过工厂)。因此,尽管必须集成到遗留代码中,但您几乎可以获得DI的所有好处。