我不得不使用已经设置好的基于 Ninject DI 的应用程序,我已经在开发我正在开发的应用程序时成长并大大增加了该应用程序。
我现在发现一个我想纠正的问题。我已经设法使用继承来解决它,但想要一个更干净的解决方案。
我需要将两个连接注入到不同的服务和存储库中。然后,我需要将存储库也正确链接到具有相同UnitOfWork
的正确服务。
我想我可能会问一些没有继承和专业化就不可能的事情,但这就是我问的原因。
我设法通过创建主Repository
和UnitOfWork
类的子类来解决此问题,但除了实现基类之外什么也没做。 我只是不喜欢一个完全依赖于超类功能的子类的想法,除了构造函数之外基本上是空的大括号,对我来说,这似乎不是真正的 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>)
{
...
}
}
我想知道的是,是否有可能通过两个不同的连接共享相同的UnitOfWork
和Repository
对象,并将它们作为不同的实例注入到各自的服务(IPOPService
用于IPOP_BE_TEST连接,QuoteService
用于IPOP_BAP连接)
同样,上面的代码没有实现我想要的,但这是我想玩的那种架构来让它工作。
你要找的是 Ninject 绑定作用域。每当您声明绑定时,Ninject 都会为该绑定提供一个委托,激活过程使用该委托来确定它是否应创建该服务的新实例,或者是否应返回以前构造的实例。
因此,如果你想在 Ninject 中实现一个单例,你只需声明一个如下所示的绑定:
Bind<IRepository<Data.Quote>>().To<Repository<Data.Quote>>().InSingletonScope();
不过,对于InScope(Func<Ninject.Activation.IContext, object> scope)
方法来说,InSingletonScope()
和InRequestScope()
只是糖(或者在InRequestScope
扩展方法的情况下IBindingInSyntax<T>
)。每当你想要确保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
时,它将创建一个使用"IPOP_BE_TESTEntities"
连接字符串初始化的UnitOfWork
实例,并且在解析IQuoteService
时,它将使用"IPOP_BAPSEntities"
连接字符串,但除此之外,在该请求范围内,Ninject 将只构造一个实例。
希望这有帮助。
你的问题对我来说并不完全清楚。但请查看以下两个作用域的文档,这两个作用域可能对你的方案感兴趣。
InCallScope
将导致每个解析树仅创建一个实例。我通常在桌面应用程序上将此范围用于工作单元。请参阅此处的文档。为此,您需要Ninject.Extensions.NamedScope
扩展。InRequestScope
将导致在 Web 应用程序中,每个 HTTP 请求只会创建一个实例。我通常将此范围用于工作单元。请参阅此处的文档。为此,您需要Ninject.Web.Common
包。