(与此问题相关的EF4:为什么在启用延迟加载后必须启用代理创建?)。
我是DI的新手,所以请多多包涵。我知道容器负责实例化我所有的注册类型,但要这样做,它需要引用我的解决方案中的所有DLL及其引用。
如果我不使用DI容器,则不必引用我的MVC3应用程序中的EntityFramework库,而只需引用我的DAL / Repo层的业务层即可。
我知道最终所有DLL都包含在bin文件夹中,但是我的问题是必须能够通过VS中的“添加引用”显式引用它,以便能够发布包含所有必要文件的WAP。
(与此问题相关的EF4:为什么在启用延迟加载后必须启用代理创建?)。
我是DI的新手,所以请多多包涵。我知道容器负责实例化我所有的注册类型,但要这样做,它需要引用我的解决方案中的所有DLL及其引用。
如果我不使用DI容器,则不必引用我的MVC3应用程序中的EntityFramework库,而只需引用我的DAL / Repo层的业务层即可。
我知道最终所有DLL都包含在bin文件夹中,但是我的问题是必须能够通过VS中的“添加引用”显式引用它,以便能够发布包含所有必要文件的WAP。
Answers:
如果我不使用DI容器,则不必在MVC3应用程序中引用EntityFramework库,而只需引用我的DAL / Repo层的业务层即可。
是的,这正是DI难以避免的情况:)
使用紧密耦合的代码,每个库可能只有几个引用,但是这些又具有其他引用,从而创建了深层的依赖关系图,如下所示:
因为依赖关系图很深,所以意味着大多数库都沿着许多其他依赖关系拖动-例如,在图中,库C沿着库H,库E,库J,库M,库K和库N拖动。这使得很难独立于其他库来重用每个库,例如在单元测试中。
但是,在松散耦合的应用程序中,通过将所有引用移动到Composition Root,依赖关系图将严重展平:
如绿色所示,现在可以重用库C,而不会拖延任何不需要的依赖项。
然而,所有的说,很多DI容器,你不要有硬引用添加到所有需要的库。相反,您可以以基于约定的程序集扫描(首选)或XML配置的形式使用后期绑定。
但是,执行此操作时,必须记住将程序集复制到应用程序的bin文件夹中,因为该操作不再自动发生。就个人而言,我很少觉得值得付出额外的努力。
可以从我的书《依赖注入,原理,实践,模式》的摘录中找到该答案的更详尽的版本。
如果我不使用DI容器,则不必在MVC3应用程序中引用EntityFramework库。
即使使用DI容器,也不必让MVC3项目引用EF,但您(隐式)选择通过在MVC3项目中实现Composition Root(组成对象图的启动路径)来选择这样做。如果对使用程序集保护体系结构边界非常严格,则可以将表示逻辑移至其他项目。
当您将所有与MVC相关的逻辑(控制器等)从启动项目移到类库时,它允许此表示层程序集与应用程序的其余部分保持断开连接。您的Web应用程序项目本身将成为具有所需启动逻辑的非常薄的外壳。该Web应用程序项目将是引用所有其他程序集的“合成根”。
使用MVC时,将表示逻辑提取到类库会使事情复杂化。由于控制器不在启动项目中(因此视图,图像,css文件可能必须留在启动项目中),因此很难将所有内容连接起来。这可能是可行的,但将花费更多的时间来设置。
由于不利因素,我通常建议仅将合成根保留在Web项目中。许多开发人员不希望其MVC程序集依赖于DAL程序集,但这并不是真正的问题。不要忘记程序集是一个部署工件。您将代码拆分为多个程序集,以允许分别部署代码。另一方面,体系结构层是逻辑工件。在同一装配体中很可能(而且很常见)有多个层。
在这种情况下,我们最终将在同一Web应用程序项目(因此在同一程序集中)中拥有“合成根”(图层)和“表示层”。并且即使该程序集引用了包含DAL的程序集,表示层仍未引用数据访问层。这是一个很大的区别。
当然,当我们这样做时,我们将失去编译器在编译时检查该体系结构规则的能力,但这不是问题。实际上,大多数体系结构规则都不能由编译器检查,总有一些常识。而且,如果您的团队没有常识,您可以随时使用代码审查(IMO应该每个团队都这样做)。您还可以使用NDepend之类的工具(商用),该工具可帮助您验证体系结构规则。当您将NDepend与构建过程集成在一起时,当有人检查其中的代码违反了这种体系结构规则时,它会发出警告。
您可以在我的《依赖注入,原理,实践,模式》一书的第4章中阅读有关“构图根”工作原理的更详尽的讨论。
如果我不使用DI容器,则不必在MVC3应用程序中引用EntityFramework库,而只需引用我的DAL / Repo层的业务层即可。
您可以创建一个名为“ DependencyResolver”的单独项目。在此项目中,您必须引用所有库。
现在,UI层不需要NHibernate / EF或任何其他与UI不相关的库,除了Castle Windsor可以被引用。
如果要在UI层中隐藏Castle Windsor和DependencyResolver,则可以编写一个HttpModule来调用IoC注册表内容。
我只有一个StructureMap的例子:
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它应该是一个安装程序)设置。