我们的客户拥有一个庞大的遗留系统,正在从.NET 1.1升级到.NET 4.0。与此同时,将基础框架移植到WCSF 2010 for Web applications,以及Enterprise Library 5.0 ou1作为基础企业框架。 DI设施一起提供这些框架。
WCSF有效地迫使MVP和模块设计依赖于ObjectBuilder及其属性,因此Web应用程序升级遵循该模式。
Web应用程序在应用层(通过WCF)上消耗额外的应用程序服务。由于底层框架已成为企业库,Unity app块已“免费下载”。但是现有的编码风格仍然是传统的,因此与网络层不同,它没有从根本上切换到DI。
应用层的典型图层是
为什么我上面提到的样式仍然是遗留的,因为层之间的服务通信是通过在网络上传递 DataSets (并且它们很大)来实现的。此DataSet将传递到每个对象的构造函数中。例如。伪造的代码
BF.SomeExposedMethod(StrongTypeDS ds)
{
this.BeginTransaction();
BizComp bc = new BizComp(ds);
bc.ShareTransaction();
bc.DoWork();
this.CommitTransaction();
}
BC.DoWork()
{
DataAccess da = new DataAccess(this.transaction, this.ds);
// perform work
da.SaveWork(this.ds);
}
这些类的构造函数还基于其父抽象类的样式;他们希望在实例化时接收DataSet。
我一直在阅读Mark Seeman的 DI in .NET 一书和其他各种有关DI问题的公共互联网资料。我似乎从所有这些讨论中理解的是,DI看起来很适合准备好干净对象的图表,以便做好工作。干净我的意思是没有上下文数据。这些遗留代码模式的构造函数从一开始就期望工作数据和上下文。
如果我正确理解了Composition Root的原理,那么必须重新设计构造函数和方法,以便通过属性传递上下文DataSet。我不清楚DI容器(在这种情况下是Unity)如何能够自己找出要注入的DataSet。确定它不能是一个空的全新DataSet。在这个开发阶段(我没有直接参与项目但是从侧面支持),我将无法建议对WCF实现进行根本性更改,以便在实例化Facade对象之前使其成为组合根。
此外,我还没有收集有关DI如何应用于基于运行时条件实例化对象的重要建议?基于数据的执行状态,可以实例化附加对象,并且类型可以基于数据类别而不同。在这个应用程序中引入某种级别的DIP和DI练习似乎是最简单的方法是将Unity容器用作服务定位器;根据需要仅在执行点抓取一个实例。
更新回答
根据Mark Seeman的建议,我制作了以下POC
使用Unity容器的BF。虽然我已经成功地尝试了Unity.Wcf包,但我还为每个BF创建了下一个最接近的组合根,其中每个facade方法将调用容器来解析执行方法工作所需的对象图。 (考虑到这种情况,这种环境可能会更加现实。)
static ExampleBF()
{
container = new UnityContainer().LoadConfiguration();
}
BF获得一个已解析的IBCFactory,它将实例化一个具有传入的实时上下文数据的具体BC。
DataSet IExampleService.GetProducts(DataSet ds)
{
IExampleBC bc = container.Resolve<IBCFactory>().CreateBC(ds);
// GetProducts() takes no parameter because DataSet already passed in on construction.
return bc.GetProducts();
}
BCFactory通过构造函数注入接收IDACFactory。它将它交给每个实例化的BC。
public BCFactory(IDACFactory DACFactory)
{
this.DACFactory = DACFactory;
}
IExampleBC IBCFactory.CreateBC(DataSet ds)
{
return new ExampleBC(this.DACFactory, ds);
}
BC将依靠IDACFactory为其提供DAC。
DataSet IExampleBC.GetProducts()
{
IExampleDAC dac = this.dacFactory.CreateDAC(this.ds);
return dac.GetProducts();
}
DACFactory类似地根据上下文数据实例化DAC。
IExampleDAC IDACFactory.CreateDAC(DataSet ds)
{
return new OrderDAC(ds);
}
当然,代码库的复杂性情况的实际情况在程度上要大一些,但是这个简单的例子应该足以向他们展示DI概念。
答案 0 :(得分:3)
据我了解相关类的描述,它们听起来更像是数据载体(实体,如果你愿意),而不是服务。如果是这样,那就是not the responsibility of the Composition Root to compose data objects。
但是,如果必须根据运行时条件解析服务,请Abstract Factory is the universal solution。
由于您正在使用遗留代码库,我想推荐一本书Working Effectively with Legacy Code,它为如何解耦紧密耦合的遗留代码库提供了很多有价值的指导。