【问题标题】:Where to put ConnectionStrings in Onion Architecture在洋葱架构中放置 ConnectionStrings 的位置
【发布时间】:2016-05-12 13:37:47
【问题描述】:

我有一个接口IApplicationConfig,它基本上包含数据库、Blob 存储和其他东西的连接字符串。对于我的解决方案中的每个“可执行”项目,例如网站、命令行工具等,都有该接口的具体实现,该接口配置为通过依赖注入解决。

我的问题是,我应该把这些IApplicationConfig-Implementations 放在哪里?

在每个“可执行”项目中我的web.config/app.config 旁边? 或者在基础设施中,如Project1Config.csProject2Config.cs 等?

【问题讨论】:

  • 由于它的组合根设置,尽可能靠近根,这可能在App_Startweb.config旁边。

标签: c# dependency-injection onion-architecture


【解决方案1】:

前言

我在我的一个应用程序中实现管理配置的方式是按照洋葱架构规则构建的,如下所示。

在这种特殊情况下,我正在考虑将管理配置(例如日志记录)作为基础设施问题,这意味着它显然不是我的应用程序核心的一部分。这是因为它是另一层。

哲学课程

要演示基础设施问题,请看下图:

* 图片来自Shawn J Lee的博客链接。

在这里您可以看到日志记录发生在基础架构切片或层中,我已经说过管理配置也是一个基础架构问题。

现在,如果您需要在架构中的任何地方获取配置管理器实现,您只需在构造函数中请求您的IApplicationConfig,并根据您最喜欢的DI container/framework 中的配置注入正确的实现。这称为Hollywood Principle 或更好的控制反转。

你说的唠叨够了吗?现在让我们直接进入技术演示...

实施概述

您已询问将实际实现放在何处。我会将这些位构造为:

  • 应用核心层
    • 域接口程序集
  • 基础设施层
    • 配置程序集
    • 依赖解析程序集
  • UI 层
    • 命令行程序集
    • 网站组装

困了是吗?现在让我们转向更高的档位。

实现示例

我将尝试在这里简要说明实际的实现细节。

域接口组件

这是您放置应用程序核心 - 以及其他层 - 将针对或使用的所有接口的层。

假设我们有IApplicationConfig.cs:

public interface IApplicationConfig
{
    ConnectionStringSettingsCollection GetConnectionStrings();
}

配置组装

这是您可以实际实现IApplicationConfig 接口的地方。把它作为一个单独的程序集是有问题的,但它实际上只是一个实现细节,我个人将我所有的配置管理实现都存储在这里。

例如IApplicationConfig 的实现可以是ApplicationConfig.cs

public class ApplicationConfig : IApplicationConfig
{
    public ConnectionStringSettingsCollection GetConnectionStrings()
    {
        return ConfigurationManager.ConnectionStrings;
    }
}

依赖解析组装

这是您将接口与所需实现“链接”的地方。这里我使用了 Ninject 并为其创建了一个 Ninject module,将其称为 ConfigModule,一个简单的例子:

public class ConfigModule : NinjectModule
{
    Bind<IApplicationConfig>().To<ApplicationConfig>();
}

最后是命令行/网站程序集

通常这些是Composition Root 或构成对象图的应用程序的入口点。说了这么多,我们现在只需要加载我们的 Ninject 模块:

private static IKernel CreateKernel()
{
    var kernel = new StandardKernel();

    var modules = new List<INinjectModule>
        {
            new ConfigModule(),
            new WhateverModule(),
            ...
        };

    kernel.Load(modules);
}

您需要添加命令行/网站程序集的参考

将接口契约和它的实现分开,这里你只需要添加对:

  • 依赖解析程序集
  • 域接口程序集

现在您可以在任何您想要的层中使用您的实现。

后记

这个例子取自我的一个实际应用,如果你不同意命名事物,我同意......这是not an easy thing来做的。

【讨论】:

  • 这正是我的做法。所以你基本上说这是一个在哪里放置配置的实现细节
  • @Sandro 是的,我认为确实如此。
  • @Sandro 你有没有成功完成这个任务?
  • 是的,我将IApplicationConfig 留在了核心项目中。每个应用程序(入口点)都需要一个实现。
  • 是的,听起来不错,你已经做到了。
【解决方案2】:

我会让接口更具体,以便它指定特定类或该程序集所需的内容,而不是应用程序所需的内容。如果您的数据访问在其自己的程序集中,则 ISettings 应该特定于该程序集,而不是与主机应用程序共享。然后我还将实现放在需要它的程序集中。宿主应用程序不应“知道”另一个程序集使用的 ISettings 接口,也不应负责创建或提供实现。

如果实现要从 app.config/web.config 读取,那么如果这些设置丢失,我会确保它抛出详细的异常。这样,依赖该程序集的人就不必猜测需要什么设置。

数据访问程序集的 DI 配置应驻留在该数据访问程序集或完全位于另一个程序集中。宿主应用程序不必“了解”太多关于其他程序集的信息,因为它包含这些程序集的详细注册。宿主应用程序只是调用一些外部安装程序来注册该程序集的依赖项。

将您的 DI 配置放在自己的程序集中也可能有意义。 (例如here 使用 Windsor。)这样,数据访问程序集是为依赖注入而构建的,但不依赖于任何一个 DI 容器。如有必要,您可以根据需要创建 Windsor 安装程序、Autofac 安装程序等(取决于您的环境或预期的使用情况,这可能是多余的。)

【讨论】:

  • 我已经有一个自己的依赖关系解决程序集,其中 DI 配置组织在模块中。数据访问在 Infrastructure 中,但这是否意味着检索其 ConnectionString 应该在同一个程序集中?
  • 理想情况下,任何程序集都需要配置数据,这就是接口和实现应该在的地方。这样它是独立的。
  • 接口不应该都进Core吗?
  • 问题是接口是否仅在程序集内部使用,或者它是否是程序集相互通信的接口。如果数据访问程序集需要一些设置来操作,那么任何其他程序集都没有理由处理它(即使这些设置出现在它的 .config 文件中。)其他程序集唯一需要做的就是调用一些配置DI。但他们不需要知道 DI 正在配置什么的详细信息。
猜你喜欢
  • 2015-05-07
  • 1970-01-01
  • 2021-08-29
  • 2011-10-09
  • 2014-10-15
  • 1970-01-01
  • 2014-06-22
  • 2015-03-17
  • 1970-01-01
相关资源
最近更新 更多