在AUTOFAC中使用不同的JSON配置文件作为相同的接口

时间:2017-06-20 09:16:41

标签: c# autofac

我正在使用Autofac JSON文件在我的项目中为同一个接口注册两个类。

如果我这样做:

JSON配置文件1:

{
  "components": [
    {
      "type": "Services.FirstProvider, Services",
      "services": [
        {
          "type": "Services.IHotelProvider, Services"
        }
      ],
      "parameters": {
        "username": "<user>",
        "password": "<pwd>"
      }
    }
  ]
}

JSON配置文件2:

{
  "components": [
    {
      "type": "Services.SecondProvider, Services",
      "services": [
        {
          "type": "Services.IHotelProvider, Services"
        }
      ],
      "parameters": {
        "key": "<key>",
      }
    }
  ]
}

并注册:

config.AddJsonFile("First/FirstProviderConfig.json");
config.AddJsonFile("Second/SecondProviderConfig.json");

我可以看到只有SecondProvider已经注册。并切换注册:

config.AddJsonFile("Second/SecondProviderConfig.json");
config.AddJsonFile("First/FirstProviderConfig.json");

仅注册了FirstProvider

如果我尝试在同一个文件中注册它们:

{
  "components": [
    {
      "type": "Services.FirstProvider, Services",
      "services": [
        {
          "type": "Services.IHotelProvider, Services"
        }
      ],
      "parameters": {
        "username": "<user>",
        "password": "<pwd>"
      }
    },
    {
      "type": "Services.SecondProvider, Services",
      "services": [
        {
          "type": "Services.IHotelProvider, Services"
        }
      ],
      "parameters": {
        "key": "<key>"
      }
    }
  ]
}

有效。

我需要分隔文件来配置它们。我错过了什么?

1 个答案:

答案 0 :(得分:5)

这里的关键点是你现在使用Microsoft.Extensions.Configuration作为配置文件的基础,这意味着配置在某种程度上受Microsoft.Extensions.Configuration行为的控制。

当您进行配置时,Microsoft.Extensions.Configuration想要处理它的方式是 覆盖设置,因为您将一个配置提供程序放在另一个之上。

在简单的情况下,假设您有两种配置:

{
  "my-key": "a"
}

{
  "my-key": "b"
}

它不会创建所有可能值的数组;它会根据键(my-key)的匹配和覆盖将第二个层叠在第一个上,以使其值为b

解析JSON配置时,它会将所有内容展平为键/值对。与XML相同。这样做是因为配置支持环境变量和INI文件以及各种其他后备存储。

对于上述非常简单的文件,你得到

my-key == b

美好而平坦。看一些更复杂的事情:

{
  "top": {
    "simple-item": "simple-value",
    "array-item": ["first", "second"]
  }
}

它变得像以下一样扁平化:

top:simple-item == simple-value
top:array-item:0 == first
top:array-item:1 == second

注意数组(“序数集合”)如何变平?每个项目都会自动分配一个假的“密钥”,该密钥具有从0开始的索引。

现在想想两个配置文件将如何分层。如果我有上面更复杂的配置然后把它...

{
  "top": {
    "array-item": ["third"]
  }
}

那个变平了

top:array-item:0 == third

看看我要去哪里?你在第一个上覆盖覆盖配置,你得到:

top:simple-item == simple-value
top:array-item:0 == third
top:array-item:1 == second

数组不组合,键/值设置覆盖

您在JSON表示中看到它们,但它们只是键/值对。

您有两种选择来尝试解决此问题。

选项1:捏造数组(不推荐)

由于您的第一次配置是(简化):

{
  "components": [
    {
      "type": "Services.FirstProvider, Services",
      "services": [ ...]
    }
  ]
}

你可以通过在第二个“覆盖”配置中放入一个虚拟空元素来“稍微捏一下”:

{
  "components": [
    {
    },
    {
      "type": "Services.SecondProvider, Services",
      "services": [ ...]
    }
  ]
}

最后我检查过,覆盖的东西只是加法的,所以空值不会擦除以前设置的值。通过将第二个配置中的数组移动1,它将改变键/值表示的扁平版本,并且两个数组应该以您希望的方式“合并”。

但那很难看,我也不会这样做。我只是想告诉你一种让它发挥作用的方法让你明白为什么你所做的不起作用。

选项2:两个独立的配置模块(推荐)

不是尝试组合两个JSON文件,而是通过单独加载JSON文件来创建两个单独的IConfiguration对象。在两个不同的ConfigurationModule注册中单独注册它们。如果其中一个配置为空,它不应该爆炸。

var first = new ConfigurationBuilder();
first.AddJsonFile("autofac.json", optional: true);
var firstModule = new ConfigurationModule(first.Build());
var second = new ConfigurationBuilder();
second.AddJsonFile("autofac-overrides.json", optional: true);
var secondModule = new ConfigurationModule(second.Build());
var builder = new ContainerBuilder();
builder.RegisterModule(firstModule);
builder.RegisterModule(secondModule);

如果配置为空或丢失,则不会注册任何内容。如果它在那里,它会。如果您想要覆盖事物或添加到您的处理程序集以获得良好的IEnumerable<T>分辨率,这应该可行。