我一直在研究如何设计一个遵循依赖性倒置原则的MVC 4 Web解决方案,并使用一个流畅配置的依赖注入(DI)容器(即使用编译时类型检查)。
我发现ASP.NET MVC 4 Dependency Injection的许多例子都集中在将MV实现到MVC框架提供的入口点的具体细节上。我发现自己倾向于采用分层方法(用红色箭头显示依赖关系): 遗憾的是,重复传统的依赖模型,其中高级模块依赖于低级模块。遵循依赖性倒置原则,IService接口被移动到WebProject中。不幸的是,这在两个项目之间创建了循环引用: 为了避免循环引用,CompositionRoot被移动到它自己的Project中:
让我解决如何引导容器的问题(现在我无法直接从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时经常发生构建目标冲突,我对这种方法并不完全满意。
我非常有兴趣听取其他经验和方法来满足这些要求。我应该放弃编译时配置并采用基于文本的配置吗?是否有一个明显的层结构,避免了我没有看到的循环依赖的陷阱?
答案 0 :(得分:0)
组合根与DI容器不同。组合根是可执行文件的最早入门级,DI Container放在那里。
DI Container放置的原因之一是,因为任何其他类都没有调用入口级别。因此,当您在那里创建DI容器时,它将确保在最早的调用时构建DI容器,并防止空引用异常。可能还有其他好处,但我只是不知道。
我通常使用的是分层设计,包括:
此设计必须更喜欢良好的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) <----------+
没有循环引用,每个人都得到他们想要的东西,只与他们需要的人交谈。