我应该将 IOC 容器的配置从 UI 中抽象出来吗?
我们的团队一直在构建一个 DDD 应用程序,该应用程序具有严格定义的应用程序服务层,该服务层构建为系统的“API”。它负责将域和基础设施中的所有内容整合在一起以完成通用任务。它只使用 DTO 作为输入/输出,因此域永远不会暴露在这一层之外。
现在我们想添加一个依赖注入容器,但我们面临着一些艰难的选择。我们有两个使用应用程序服务来完成工作的客户端应用程序:一个 MVC 2 应用程序和一个 Windows 服务应用程序。传统上,使依赖注入工作的所有配置代码都放在mvc项目中的global.asax文件中,我见过很多这样的例子。问题是 IOC 注册代码随后在 Windows 服务中重复,并针对该平台进行了轻微修改。
我遇到的问题是 DI 要求客户端应用程序知道注册什么以及如何注册,这还要求客户端应用程序引用域和基础设施层。拥有应用程序服务层的整个想法是,这是客户应该了解和交谈的唯一内容。我提出的解决方案是在我的应用程序服务层中创建一个“依赖服务”,客户端将调用一次该服务,并且它将配置 DI 容器,因为它知道需要什么。它还具有允许客户端应用程序注册其自己的附加依赖项的方法。例如,MVC 项目将注册其控制器工厂,Windows 服务将注册其启动类。我想知道这是否不常见,或者我的这个想法是否走错了路。以前有其他人遇到过这个问题吗?
Our team has been building a DDD app that has a strongly defined application service layer that is built as the "API" of the system. It handles pulling everything together from the domain and infrastructure to accomplish generic tasks. It uses nothing but DTOs as input/output so the domain is never exposed beyond this layer.
Now we want to add a dependency injection container into the mix and we are faced with some tough choices. We have two client applications that use the application services to do their work: an MVC 2 app and a windows service app. Traditionally all the configuration code to make dependency injection work is put in the global.asax file in the mvc project, which I have seen numerous examples of. The problem is that IOC registration code is then duplicated in the windows service and modified slightly for that platform.
The problem I have is that DI requires the client app to know what to register and how, which also requires the client app to have references to the domain and infrastructure layers. The whole idea with having an app services layer was that it was the only thing clients should know and talk to. My proposed solution was to create a "Dependency Service" in my app service layer that clients would call once, and it would configure the DI container since it knows what is required. It would also have methods to allow the client app to register additional dependencies of its own. For example the MVC project would register its controller factory, and the windows service would register its startup class. I wanted to know if this is uncommon or if I am on the wrong path with this idea. Has anyone else come across this issue before?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
给猫剥皮的方法有很多种;然而,您似乎采取了错误的方法。应用程序的入口点(Global.asax 或 Program.cs)绝对应该是选择要在 IoC 容器中配置的组件的位置。另一方面,您的服务通常不应嵌入任何 IoC 配置知识。我的猜测是您已经遵循了这一原则,但由于重复配置而正在重新检查它。
为了在不重复代码的情况下实现这一点,正如您所描述的,许多 IoC 容器提供了模块化结构,封装了一组相关组件的配置。在 Autofac(和 Ninject IIRC)中,这些被称为“模块” - http://code.google .com/p/autofac/wiki/StructuringWithModules。 Castle Windsor 称它们为“安装程序”,而 StructureMap 称它们为“注册表”。
通过将配置分解为模块,减少了应用程序启动方法中的配置代码量。在您的示例中,为了简化起见,您可以创建三个模块:
CoreModule 将包含在每个执行环境中共享且行为相同的组件的配置。
WebModule 和 ServiceProcessModule 将包含特定于这些环境的组件的注册,以及根据主机进行不同配置的任何共享组件的专门配置。
您的 Web 应用程序启动将类似于:
虽然服务流程非常相似,但用 WebModule 替换 ServiceProcessModule。
与使用条件代码的静态初始化方法相比,这种配置风格将更好地扩展到许多应用程序入口点和/或许多组件子系统。
希望这有帮助。
缺口
There are many ways to skin a cat; it seems like you're taking the wrong approach however. The entry point of the application (Global.asax or Program.cs) should absolutely be the place that selects the components to be configured in the IoC container. Your services, on the other hand, generally shouldn't have any IoC configuration knowledge embedded in them. My guess is you're already following this principle but are reexamining it because of the repetitive configuration.
To make this feasible without code repetition, as you've described, many IoC containers provide modularisation constructs that encapsulate the configuration of a set of related components. In Autofac (and Ninject IIRC) these are called 'modules' - http://code.google.com/p/autofac/wiki/StructuringWithModules. Castle Windsor calls them 'installers' while StructureMap calls them 'registries'.
By factoring configuration into modules, the amount of configuration code in the application startup method is reduced. In your example, as a simplification, you may create three modules:
The CoreModule would contain configuration for the components that are shared and behave identically in each of the execution environments.
WebModule and ServiceProcessModule would contain registrations for components specific to those environments, plus specialised configuration of any shared components that are configured differently depending on the host.
Your web app startup would then be something like:
While the service process would be very similar but substituting WebModule for ServiceProcessModule.
This style of configuration will scale much better to many application entry points and/or many subsystems of components, when compared with the static initialisation method with conditional code.
Hope this helps.
Nick
我将一个配置类放入 DDD 或 DomainModel 项目中,并在 UI 中调用该配置类。
在您的 UI 中,您只需调用 Initialize() 方法即可。您可以在 MVC Global.asax 甚至 Windows 服务应用程序中使用它。没有代码重复。
对我来说效果很好。
I put a configuration class into my DDD or DomainModel project and call the configuration class in the UI.
In your UI you have to call only the Initialize() method and thats all. You can use it in your MVC Global.asax and even in your windows service app as well. No code duplication.
Works very well for me.