nTier 中的依赖关系注入 + 运行时解析
本文关键字:运行时 注入 关系 依赖 nTier | 更新日期: 2023-09-27 18:35:00
我一直在阅读依赖注入(Mark Seemann:.NET 中的依赖注入和各种文章(,以帮助我的团队开发基于 EntityFramework、WCF 和 WPF 的新 3 层应用程序。
我假设我们在每个层上都需要一个组合根,因为它们通过服务进行通信(DAL <-> WCF <-> BL <-> WCF <-> PL/UI(。
我们的要求之一是我们需要动态加载和配置 EF,以便在应用程序部署后可以更改/扩展模型。
在不详细介绍我们的 BL --> PL/UI 实现的情况下,让我们关注通过自定义服务主机后面的实体服务公开的 DAL。我们的项目有一个简单的例子,布局如下:
Project.DataModel
- 单个组件
- 硬参考:无
- 运行时分辨率:无
- 一个公共库,它为抽象类和数据建模提供了接口。 即实体数据抽象类
项目.数据模型.[?]数据
- 许多程序集:即城市数据,客户数据等
- 硬引用:Project.DataModel
- 运行时分辨率:无
- 定义基于实体数据的单个或多个实体的组件
项目.数据模型.[?]数据配置
- 许多程序集:即CityDataConfiguration,CustomerDataConfiguration等
- 硬参考:Project.DataModel.[?]数据,实体框架
- 运行时分辨率:无
- 为上一个程序集中定义的实体定义实体类型配置的组件。
Project.DataAccess
- 单个组件
- 硬引用:Project.DataModel,EntityFramework
- 运行时解析:Project.DataModel.[?]数据,项目.数据模型。[?]数据配置
- 通过 EntityManager(抽象(提供 DbContext 的数据访问库。在运行时,此程序集查看配置或目录,加载实体类型及其等效的实体类型配置,并动态创建模型。
Project.ServiceModel.EntityDataService
- 单个组件
- 硬引用:Project.DataModel,Project.DataAccess
- 运行时分辨率:无
- 一种通用服务,通过 EntityManager 类对实体数据对象提供 CRUD 操作。
Project.ServiceModel.EntityDataServiceContract
- 单个组件
- 硬引用引用:Project.DataModel
- 运行时解析:Project.DataModel.[?]数据
- 公开服务协定并需要定义 ServiceKnownType,因此我们需要 EntityType 的运行时解析。
项目服务主机
- 单个组件
- 硬参考:无
- 运行时解析:Project.ServiceModel.[?]服务,项目.服务模型。[?]服务合同
- 自定义服务主机,将在运行时(通过配置或目录扫描(解析和加载各种服务,如实体数据服务。
这感觉很像一个插件项目,我们在编译时知道的不多,程序集之间没有太多硬引用。
在这种情况下,您将如何实现 DI。我真的无法确定如何以及在何处使用 DI 或 DI 容器、组合根和很多。
非常感谢您的意见。
人们有办法使依赖注入过于复杂。如果 FirstClass 需要一个 ISecondClass 来工作,那么只要确保没有 ISecondClass 就无法构建它。组合根本质上是一个类,你可以遵循其依赖项到其他所有内容。确保你的接口都有注册的实例(单例生存期通常可以很好地完成工作(,实例化组合根,大多数东西应该"正常工作"。如果没有,则某些事情比需要的要复杂得多。
WizBang应用程序可能如下所示:
interface IThingDoerA
{
}
class ThingDoerA : IThingDoerA
{
}
interface IThingDoerB
{
}
class ThingDoerB : IThingDoerB
{
private readonly IThingDoerA _tda;
public ThingDoerB(IThingDoerA tda)
{
_tda = tda;
}
}
interface IThingDoerC
{
}
class ThingDoerC : IThingDoerC
{
private readonly IThingDoerA _tda;
private readonly IThingDoerB _tdb;
public ThingDoerC(IThingDoerA tda, IThingDoerB tdb)
{
_tda = tda;
_tdb = tdb;
}
}
// I am the composition root.
interface IWizBang
{
public void StartApp();
}
class WizBang : IWizBang
{
private readonly IThingDoerA _tda;
private readonly IThingDoerC _tdc;
public WizBang(IThingDoerA tda, IThingDoerC tdc)
{
_tda = tda;
_tdc = tdc;
}
public void StartApp()
{
//TODO
// _tda.Blah()
// _tdc.Blah()
}
}
就 WPF 而言,看起来您可以在 System.Windows.Application 子类中执行一些轻量级方法调用来运行您的应用程序。