在ASP.NET MVC 4解决方案中使用编译时配置依赖注入的依赖性反转

时间:2013-05-23 20:52:35

标签: c# asp.net-mvc-4 dependency-injection circular-dependency solid-principles

我一直在研究如何设计一个遵循依赖性倒置原则的MVC 4 Web解决方案,并使用一个流畅配置的依赖注入(DI)容器(即使用编译时类型检查)。

我发现ASP.NET MVC 4 Dependency Injection的许多例子都集中在将MV实现到MVC框架提供的入口点的具体细节上。我发现自己倾向于采用分层方法(用红色箭头显示依赖关系): enter image description here 遗憾的是,重复传统的依赖模型,其中高级模块依赖于低级模块。遵循依赖性倒置原则,IService接口被移动到WebProject中。不幸的是,这在两个项目之间创建了循环引用: enter image description here 为了避免循环引用,CompositionRoot被移动到它自己的Project中: enter image description here

让我解决如何引导容器的问题(现在我无法直接从WebProject中引用它)?

the best way to get the directory from which an assembly is executing的帮助下,通过反射可以实现初始化。

var assembly = System.Reflection.Assembly.LoadFile(Helper.AssemblyDirectory + "/DependencyInjectionProject.dll");
var type = assembly.GetType("DependencyInjectionProject.Bootstrapper");
IDependencyResolver resolver = (IDependencyResolver)type.GetMethod("Initialise").Invoke(null, null);
DependencyResolver.SetResolver(resolver);

为了简化构建,我将DependencyInjectionProject的构建目标设置为WebProject bin目录。我实现了目标;反向依赖关系和编译时检查容器配置但由于在IIS Express中运行WebProject时经常发生构建目标冲突,我对这种方法并不完全满意。

我非常有兴趣听取其他经验和方法来满足这些要求。我应该放弃编译时配置并采用基于文本的配置吗?是否有一个明显的层结构,避免了我没有看到的循环依赖的陷阱?

2 个答案:

答案 0 :(得分:0)

组合根与DI容器不同。组合根是可执行文件的最早入门级,DI Container放在那里。

DI Container放置的原因之一是,因为任何其他类都没有调用入口级别。因此,当您在那里创建DI容器时,它将确保在最早的调用时构建DI容器,并防止空引用异常。可能还有其他好处,但我只是不知道。

我通常使用的是分层设计,包括:

  1. 域名模型(实体)
  2. 接口(参考文献1)
  3. 服务(参考文献1和2)
  4. dal(参考文献1和2)
  5. UI(参考1,2,3,4)
  6. 此设计必须更喜欢良好的SOC,并且可以阻止UI直接访问存储库。 dal不了解服务和UI。该服务不了解DAL和UI。

    我知道的一个缺点是这种设计允许UI直接访问DAL而无需服务。

    我仍然不知道这个设计的其他缺点。

答案 1 :(得分:-1)

您永远不会想将IService转移到Web项目中。除了循环引用(不一定是交易破坏者,虽然VS不会让你这样做......它可以通过其他几种方式完成),这只是糟糕的设计。

高级模块绝对没有问题,取决于较低级别的模块。我不确定你为什么认为这是一个问题。依赖性反转并不真正引用模块或程序集依赖性,它指的是接口依赖性。 (我在这里一般说,而不是具体关于interface关键字)。实际上,你可以在没有任何单独组件的情况下使用DI ......它们都可以在同一个组件中。

但是,如果您选择将实现拆分为单独的程序集,则存在某些限制。这些主要是装配系统的实施问题。

模块依赖关系的问题实际上并没有显示只有两个模块。当你有3个或更多时,这就更成问题了。

我喜欢自己使用洋葱建筑。在此方法中,您有一个单独的程序集,其中包含您的接口和常见类型(例如实体)。这个程序集中没有很多代码,它主要是定义。

上面是您的数据层和您的业务层。这些取决于实体和接口的通用程序集。然后你有了你的UI层,这取决于你的业务(或服务层,通常只是业务层的外观)和公共层。

使用这种方法,UI无法与DAL通信,反之亦然。业务层与DAL和UI进行通信。一切都取决于具有很少功能代码的通用接口组件,只有实体,DTO和接口。因此,共同点除了核心.NET之外什么都没有。

    UI <--------> Service/Business <--------> DAL
     |                   |                     |
     +----------> Common (IService) <----------+

没有循环引用,每个人都得到他们想要的东西,只与他们需要的人交谈。