Ninject的依赖注入共享具有不同实例的相同对象

时间:2016-11-25 15:08:57

标签: c# asp.net-mvc dependency-injection ninject

我已经得到了一个已经设置好的基于Ninject DI的应用程序,我已经成长并在我正在开发的应用程序的开发中大大增加了。

我现在发现了一个我想纠正的问题。我设法使用继承来解决它,但希望有一个更清洁的解决方案。

我需要将两个连接注入不同的服务和存储库。然后,我需要将存储库正确链接到具有相同UnitOfWork的正确服务。

我想如果没有继承和专业化,我可能会问一些不可能的事情,但这就是我要问的原因。

我设法通过创建主RepositoryUnitOfWork类的子类来解决这个问题,但除了实现基类之外什么也没做。 我只是不喜欢一个完全依赖于超类功能的子类的想法,除了构造函数之外基本上是空的括号,对我而言,这似乎不是真正的OOP来解决这个问题。因此,如果可能,我会在DI中寻求一种更好的解决方案,使用一类解决方案。

所以,如果你可以忽略我所说的解决方案,因为我完全恢复了改变,这就是我留下的:

查看下面的代码,您可以看到目标是什么。

...

public class UnitOfWork : IUnitOfWork
{
    private static readonly log4net.ILog log = log4net.LogManager.GetLogger("UnitOfWork");
    public DbContext DataContext { get; set; }

    public UnitOfWork(string connectionString)
    {
        DataContext = new DbContext(connectionString);
    }

    public void Commit()
    {
        ...
    }
}

...

public class Repository<T> : IRepository<T> where T : class
{
    public IUnitOfWork unitOfWork { get; set; }
    private readonly IDbSet<T> dbSet;

    //private static readonly log4net.ILog log = log4net.LogManager.GetLogger("Repository");

    public Repository(IUnitOfWork unitOfWork)
    {
        this.unitOfWork = unitOfWork;
        dbSet = this.unitOfWork.DataContext.Set<T>();
    }
    ...
}
...

public class IPOPDataModules : NinjectModule
{
    public override void Load()
    {
    Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope().WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BE_TESTEntities"].ConnectionString);
    Bind<IRepository<tOrder>>().To<Repository<tOrder>>().InRequestScope();
    }
}

...

public class DataModules : NinjectModule
{
    public override void Load()
    {
    Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope().WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BAPSEntities"].ConnectionString);
    Bind<IRepository<Data.Quote>>().To<Repository<Data.Quote>>().InRequestScope();
    }
}

...

public class QuoteService : IQuoteService
{
    private IUnitOfWork unitOfWork;
    private IRepository<Data.Quote> quoteRepository;
    public QuoteService(IUnitOfWork unitOfWork, IRepository<Data.Quote> quoteRepository)
    {
        ...
    }
}

...

public class IPOPService : IIPOPService
{
    private IUnitOfWork unitOfWork;
    private IRepository<Data.tOrder> tOrderRepository;

    public IPOPService(IUnitOfWork unitOfWork, IRepository<Data.tOrder>)
    {
        ...
    }
}

我想知道的是,是否可以通过两个不同的连接共享相同的UnitOfWorkRepository对象,并将它们作为不同的实例注入相应的服务(IPOPService对于IPOP_BE_TEST连接,QuoteService用于IPOP_BAP连接)

上面的代码再一次没有达到我想要的目标,但这是我想要让它发挥作用的那种架构。

2 个答案:

答案 0 :(得分:0)

你的问题对我来说并不完全清楚。但请查看以下两个范围的文档,这可能对您的方案很有用。

  • InCallScope将导致每个分辨率树只创建一个实例。我通常在桌面应用程序上使用此范围作为一个工作单元。请参阅文档here。您需要Ninject.Extensions.NamedScope扩展名。
  • InRequestScope将导致在Web应用程序中,每个HTTP请求只会创建一个实例。我通常将此范围用于工作单元。请参阅文档here。您需要Ninject.Web.Common包。

答案 1 :(得分:0)

您正在寻找的是Ninject绑定范围。每当您声明绑定时,Ninject将为该绑定提供一个委托,激活进程使用该委托来确定它是否应该创建该服务的新实例,或者它是否应返回先前构造的实例。

所以,如果你想在Ninject中实现一个单例,你只需要声明一个如下所示的绑定:

Bind<IRepository<Data.Quote>>().To<Repository<Data.Quote>>().InSingletonScope();

InSingletonScope()InRequestScope()对于InRequestScope方法而言IBindingInSyntax<T>只是糖(或InScope(Func<Ninject.Activation.IContext, object> scope)扩展方法的情况下)。每当您想确保Ninject在给定情况下返回相同的服务实例时,您需要做的就是实现自定义范围。

如果我正确理解您的问题,您需要确保当请求到达您的应用程序时,Repository<T>IUnitOfWork的相同实例将被注入您的应用程序中的所有服务。在这种情况下,您只需要编写这样的绑定:

Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope().WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BE_TESTEntities"].ConnectionString);
Bind<IRepository<tOrder>>().To<Repository<tOrder>>().InRequestScope();

但是,您的问题似乎是您有两个单独的模块,具有两个单独的绑定。我建议您需要使用具有上下文绑定的单个模块来确定应该将哪个连接字符串提供给系统的哪个部分。所以你的一个模块看起来像这样:

Bind<IUnitOfWork>()
    .To<UnitOfWork>()
    .WhenInjectedInto<IIPOPService>()
    .InRequestScope()
    .WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BE_TESTEntities"].ConnectionString);
Bind<IUnitOfWork>()
    .To<UnitOfWork>()
    .WhenInjectedInto<IQuoteService>()
    .InRequestScope()
    .WithConstructorArgument("connectionString", ConfigurationManager.ConnectionStrings["IPOP_BAPSEntities"].ConnectionString);

Bind<IRepository<tOrder>>().To<Repository<tOrder>>().InRequestScope();

通过这种方式,您可以确定当Ninject解析IIPOPService时,它会创建一个使用UnitOfWork连接字符串初始化的"IPOP_BE_TESTEntities"实例,并在解析IQuoteService时,它将使用"IPOP_BAPSEntities"连接字符串,但除此之外,在该请求范围内,Ninject只会构造一个实例。

希望这有帮助。