如何配置Ninject,使其根据先前注入的实例注入正确的实例

本文关键字:注入 实例 何配置 配置 Ninject | 更新日期: 2023-09-27 17:59:14

我找不到合适的单词来回答我的问题,所以我会让我的代码说话。

我有仓库:

class Repository
{
    public Repository(DbContext ctx)
    {
    }
}

然后我有这个绑定:

Bind<IRepository>().To<Repository>();
Bind<DbContext>().To<UserStoreContext>().When...
Bind<DbContext>().To<CentralStoreContext>().When...

然后我有一个类需要访问数据库的

class Foo
{
    public Repository(IRepository userRepo, [CentralStoreAttribute]IRepository centralRepo)
    {
    }
}

我应该如何配置两个DbContext绑定,以便将具有正确上下文(基于CentralStoreAttribute)的存储库注入Foo构造函数?

如何配置Ninject,使其根据先前注入的实例注入正确的实例

我在概念验证中尝试了这一点,但最终走向了不同的方向。

Bind<IRepository>().ToMethod(x =>
{
  var repositoryType = x.Kernel
                .Get<IConfigObject>()
                .SomeStringPropertyDenotingTheRepository;
  switch (repositoryType )
  {
    case "1": return (IRepository)new Repository1();
    default: return (IRepository)new Repository2();
  }
}).InRequestScope();

虽然它有效,但我从来没有弄清楚它是在使用IObjectB的单例实例还是实例化一个新实例——不过应该很容易弄清楚。我想每次我在IRepository上使用DI时,它都会调用ToMethod——同样没有经过验证。

使用When(Func<IRequest, bool> condition)重载检查给定请求或其一个分支r.ParentRequestr.Target.IsDefined(typeof(TAttribute), false)是否为真

我通常创建几个实际上只是别名的类型,而不是依赖于正确位置的属性。这是有用的,因为对于Ninject(以及可能的其他IoC容器),我们通过它们的类型名称来询问依赖关系。

因此,如果你需要能够"请求"一个用户存储库与一个中央存储库,我会创建这样的别名:

interface IRepository {  /* methods and properties */ }
interface IUserRepository : IRepository {}
interface ICentralRepository : IRepository {}
class Foo
{
   public Foo(IUserRepository userRepo, ICentralRepository centralRepo)
   {
      // assign to fields
   }
}

我更喜欢这样,因为Ninject根本不会渗透到我的应用程序中,它更具声明性,而且我认为它比任何基于约定的属性方法都更容易记住,比如你正在尝试的方法。

Bind<IRepository>().To<Repository>();
Bind<DbContext>().To<CentralStoreContext>()
    .When( context => context.Target != null 
        && context.Target.GetCustomAttributes( typeof( CentralStoreAttribute ) ) != null );
// make the general binding after the more specific one
Bind<DbContext>().To<UserStoreContext>();