在洋葱架构中放置 ConnectionString 的位置

Where to put ConnectionStrings in Onion Architecture

我有一个接口 IApplicationConfig,它基本上包含用于数据库、Blob 存储和其他内容的 ConnectionString。对于我解决方案中的每个 "executable" 项目,如网站、命令行工具等,都有该接口的具体实现,该接口配置为通过依赖注入来解析。

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

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

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

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

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

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

前言

我在我的一个应用程序中实现管理配置的方式如下所示。

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

哲学课程

为了展示基础设施问题,请看下图:

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

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

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

你说够啰嗦了?现在让我们直接进入技术演示...

实施概述

您询问了实际实施的位置。我会将这些位构造为:

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

困了吗?让我们现在换档。

实现示例

我将尝试在此处简要说明实际的实施细节。

域接口程序集

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

假设我们有 IApplicationConfig.cs:

public interface IApplicationConfig
{
    ConnectionStringSettingsCollection GetConnectionStrings();
}

配置程序集

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

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

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

依赖解析程序集

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

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

最后是 Commandline/Website 程序集

通常这些是 Composition Root 或您编写对象图的应用程序的入口点。话虽如此,我们现在只需要加载我们的 Ninject 模块:

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

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

    kernel.Load(modules);
}

需要添加的引用Commandline/Website程序集

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

的引用
  • 依赖解析程序集
  • 域接口程序集

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

后记

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