Ioc/DI-为什么我必须引用应用程序入口点的所有层/程序集?

(关于这个问题,EF4: 为什么在启用延迟加载时必须启用代理创建?)。

我是新来的督察,忍耐一下。我知道容器负责实例化我所有注册的类型,但是为了这样做,它需要引用解决方案中的所有 DLL 及其引用。

如果我不使用 DI 容器,我就不需要在 MVC3应用程序中引用 EntityFramework 库,只需要引用业务层,业务层会引用我的 DAL/Repo 层。

我知道在一天结束时,所有的 DLL 都包含在 bin 文件夹中,但我的问题是必须通过 VS 中的“添加引用”明确地引用它,以便能够发布包含所有必要文件的 WAP。

30359 次浏览

如果我没有使用 DI 容器,我就不需要在 MVC3应用程序中引用 EntityFramework 库,只需要在业务层中引用 DAL/Repo 层。

是的,这正是 DI 努力避免的情况:)

对于紧密耦合的代码,每个库可能只有几个引用,但是这些库也有其他引用,创建一个深度依赖关系图,如下所示:

Deep Graph

因为依赖关系图很深,这意味着大多数库会拖动许多其他依赖关系-例如,在图中,图书馆 C会拖动 图书馆 H,图书馆 E,图书馆 J,图书馆 M,图书馆 K图书馆 N。这使得独立于其他库(例如 在单元测试中)重用每个库变得更加困难。

然而,在一个松散耦合的应用程序中,通过移动所有对 成分根的引用,依赖图严重扁平化:

Shallow Graph

如绿色所示,现在可以重用 图书馆 C,而无需拖动任何不必要的依赖项。

尽管如此,对于许多 DI 容器,您不能使用 来添加对所有必需库的硬引用。相反,您可以以基于约定的汇编扫描(首选)或 XML 配置的形式使用 后期装订

但是,在执行此操作时,必须记住将程序集复制到应用程序的 bin 文件夹,因为这不再会自动发生。就我个人而言,我很少发现它值得我付出额外的努力。

这个答案的更详细的版本可以在我的书 依赖注入,原则,实践,模式这段摘录中找到。

如果我没有使用 DI 容器,我就不需要引用 在我的 MVC3应用程序中的 EntityFramework 库

即使在使用 DI 容器时,您也不必让 MVC3项目引用实体框架,但是您(隐式地)选择通过在 MVC3项目中实现 成分根(构建对象图的启动路径)来实现这一点。如果在使用程序集保护架构边界方面非常严格,那么可以将表示逻辑移动到不同的项目。

当您将所有与 MVC 相关的逻辑(控制器等)从启动项目移动到类库时,它允许这个表示层程序集与应用程序的其余部分保持断开连接。您的 Web 应用程序项目本身将成为一个具有所需启动逻辑的非常薄的 shell。Web 应用程序项目将是引用所有其他程序集的组合根。

在使用 MVC 时,将表示逻辑提取到类库中会使事情变得复杂。因为控制器不在启动项目中(而视图、图像、 CSS 文件可能必须保留在启动项目中) ,所以将所有东西连接起来会更加困难。这可能是可行的,但需要更多的时间来设置。

由于存在缺点,我通常建议只在 Web 项目中保留组合根。许多开发人员不希望他们的 MVC 程序集依赖于 DAL 程序集,但这应该不是问题。不要忘记程序集是 部署构件; 您可以将代码分割为多个程序集,以允许单独部署代码。另一方面,架构层是 合乎逻辑构件。在同一个程序集中有多个层是非常可能的(也是常见的)。

在这种情况下,您最终将在同一个 Web 应用程序项目(因此在同一个程序集中)中拥有组合根(层)和表示层。即使 集合引用包含 DAL 的程序集,Presentation分层仍然不引用 DAL ーー这是一个很大的区别。

当然,当您这样做时,您将失去编译器在编译时检查此体系结构规则的能力。但是大多数体系结构规则实际上不能被编译器检查。如果你担心你的团队不遵循架构规则,我建议引入代码审查,这是提高代码质量、一致性和提高团队技能的重要实践。您还可以使用 NDepend (商业性的)这样的工具,它可以帮助您验证体系结构规则。当您将 NDepend 集成到您的构建过程中时,当有人检入了违反此体系结构规则的代码时,它会发出警告。

您可以在我的书 依赖注入,原则,实践,模式的第4章中阅读关于组合根如何工作的更详细的讨论。

如果我没有使用 DI 容器,我就不需要引用 在我的 MVC3应用程序的 EntityFramework 库,只有我的业务层 将引用我的 DAL/回购层。

您可以创建一个名为“ DependencyResolver”的独立项目。 在这个项目中,你必须引用你所有的库。

现在 UI 层不需要 NHibernate/EF 或任何其他与 UI 无关的库,除了 Castle Windsor。

如果你想在 UI 层隐藏 Castle Windsor 和 DependencyResolver,你可以编写一个 HttpModule 来调用 IoC 注册表。

我只有一个结构地图的例子:

public class DependencyRegistrarModule : IHttpModule
{
private static bool _dependenciesRegistered;
private static readonly object Lock = new object();


public void Init(HttpApplication context)
{
context.BeginRequest += (sender, args) => EnsureDependenciesRegistered();
}


public void Dispose() { }


private static void EnsureDependenciesRegistered()
{
if (!_dependenciesRegistered)
{
lock (Lock)
{
if (!_dependenciesRegistered)
{
ObjectFactory.ResetDefaults();


// Register all you dependencies here
ObjectFactory.Initialize(x => x.AddRegistry(new DependencyRegistry()));


new InitiailizeDefaultFactories().Configure();
_dependenciesRegistered = true;
}
}
}
}
}


public class InitiailizeDefaultFactories
{
public void Configure()
{
StructureMapControllerFactory.GetController = type => ObjectFactory.GetInstance(type);
...
}
}

DefaultControllerFactory 不直接使用 IoC 容器,但是它委托 IoC 容器方法。

public class StructureMapControllerFactory : DefaultControllerFactory
{
public static Func<Type, object> GetController = type =>
{
throw new  InvalidOperationException("The dependency callback for the StructureMapControllerFactory is not configured!");
};


protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
return base.GetControllerInstance(requestContext, controllerType);
}
return GetController(controllerType) as Controller;
}
}

GetController委托在 structureMap 注册表中设置(在 Windsor 中,它应该是一个安装程序)。

  • 有一个依赖项: 如果一个对象实例化另一个对象。
  • 没有依赖关系: 如果对象需要抽象(构造函数注入,方法注入...)
  • 汇编引用(引用 dll,webservices)。.)独立于依赖概念,因为要解析抽象并能够编译代码,层必须引用它。