11

Onion 架构是一种构建应用程序以保持关注点分离和松散耦合的方式(示例项目位于:http : //onionarch.codeplex.com/)。依赖注入/解决是该架构的一个关键方面,因为它用于将所有层联系在一起。

上面的链接包含一个关于如何使用 Onion 分层构造 ASP.NET MVC 的示例应用程序。我真的很喜欢它,但是这些示例中的大多数都使用 Ninject(我们都知道它很慢)。我想知道是否有人可以详细说明如何将不同的 DI 工具(如 SimpleInjector、Unity 或 Autofac)集成到 Onion 项目中。

关键是所有层都只有1个依赖(包括MVC项目),即Core层。除了 Dependency Resolution 层,该层可以引用所有层。

我很难将 MVC 项目设置为启动项目,使用 DI,并且不包括在 MVC 层中对 DI 工具的引用。

4

2 回答 2

16

你的问题是

“如何将不同的 DI 工具(如 SimpleInjector、Unity 或 Autofac)集成到 Onion 项目中?”

我使用的是 StructureMap 而不是 Ninject,它的集成方式应该适用于任何其他 DI 框架。

正如你所说,只有依赖解析层应该引用所有其他层,它是洋葱架构的最外层。好吧,为此,我创建了一个名为BootStrapper的项目。这是我引用 StructureMap 程序集的唯一项目。在这个项目的App_Start文件夹中,我有一个名为StructureMapMvc.cs的文件,如下所示:

[assembly: WebActivator.PreApplicationStartMethod(typeof(XXXX.BootStrapper.App_Start.StructuremapMvc), "Start")]

namespace XXXX.BootStrapper.App_Start
{
    public static class StructuremapMvc
    {
        public static void Start()
        {
            IContainer container = IoC.Initialize();
            System.Web.Mvc.DependencyResolver.SetResolver(new StructureMapDependencyResolver(container));
            GlobalConfiguration.Configuration.DependencyResolver = new StructureMapHttpDependencyResolver(container);
            ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
        }
    }
}

有趣的是:

[assembly: WebActivator.PreApplicationStartMethod(typeof(XXXX.BootStrapper.App_Start.StructuremapMvc), "Start")]

根据 nugget 包的描述:

WebActivator 是一个 NuGet 包,它允许其他包在 Web 应用程序中执行一些启动代码。

很酷吧?您必须完成的最后一件事是确保将BootStrapper项目程序集推送到您的 Web 应用程序的/bin文件夹(使用构建后操作或 OutputTo nugget 包轻松设置)。这将避免您在 MVC 项目中引用BootStrapper项目并打破洋葱架构原则。

因此,所有这些都到位后,它完全符合组合根模式,当您的应用程序启动时,模块将组合在一起。

希望这可以帮助!

于 2013-03-04T11:01:10.030 回答
4

请注意,我认为 Onion 架构(或者至少是您指出的示例实现,正如 @MystereMan 在评论中正确指出的那样)有一个您应该注意的问题点。

尽管该架构似乎偏爱小型/集中接口(通常只有一个成员),但这些服务的命名似乎另有说明。例如,在参考架构中,有一个IShippingService类。它有一个成员,因此它遵守接口隔离原则(这很好)。然而,“运输服务”这个名称表明它应该包含与运输相关的所有方法。那很容易有几十个。但是,向此接口添加成员会破坏接口隔离原则、单一职责原则(SRP) 和开放关闭原则(OCP)。使用许多几乎没有关系(SRP)的方法,实现将变得又大又丑。实施新的运输要求意味着添加一个成员,这会破坏 OCP。接口有很多成员,而消费者通常只需要调用其中一个成员(低内聚度),这会使单元测试更加困难。

将其分解为所有成员的接口确实解决了部分问题(架构可能有这种意图),但这会给您留下大量彼此没有关系的接口,从而难以应用交叉-将关注点(日志记录、监控、审计跟踪、验证、事务、容错等)转移给他们。

这是否是一个问题取决于很多因素,但违反SOLID原则之一始终是需要提防的。

因此,作为 Onion 架构的补充,我建议您阅读这篇文章。它描述了这个可能的缺点的解决方案,它可以应用于 Onion 架构。

于 2013-02-15T09:45:41.007 回答