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

Piz*_*sio 4 c# autofac

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

如果我做这样的事情:

JSON配置文件1:

{
  "components": [
    {
      "type": "Services.FirstProvider, Services",
      "services": [
        {
          "type": "Services.IHotelProvider, Services"
        }
      ],
      "parameters": {
        "username": "<user>",
        "password": "<pwd>"
      }
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

JSON配置文件2:

{
  "components": [
    {
      "type": "Services.SecondProvider, Services",
      "services": [
        {
          "type": "Services.IHotelProvider, Services"
        }
      ],
      "parameters": {
        "key": "<key>",
      }
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

并注册:

config.AddJsonFile("First/FirstProviderConfig.json");
config.AddJsonFile("Second/SecondProviderConfig.json");
Run Code Online (Sandbox Code Playgroud)

我可以看到只有SecondProvider已登记.并切换注册:

config.AddJsonFile("Second/SecondProviderConfig.json");
config.AddJsonFile("First/FirstProviderConfig.json");
Run Code Online (Sandbox Code Playgroud)

只是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>"
      }
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

有用.

我需要分离文件来配置它们.我想念的是什么?

Tra*_*lig 5

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

配置时,Microsoft.Extensions.Configuration要处理它的方式是在将一个配置提供程序层叠在另一个配置提供程序之上时覆盖设置.

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

{
  "my-key": "a"
}
Run Code Online (Sandbox Code Playgroud)

{
  "my-key": "b"
}
Run Code Online (Sandbox Code Playgroud)

它不会创建所有可能值的数组; 它将第二个基于key(my-key)匹配并覆盖第一个,以获得值b.

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

在上述非常简单的文件的情况下,你得到

my-key == b
Run Code Online (Sandbox Code Playgroud)

漂亮而平坦.看一些更复杂的事情:

{
  "top": {
    "simple-item": "simple-value",
    "array-item": ["first", "second"]
  }
}
Run Code Online (Sandbox Code Playgroud)

它像以下一样变平:

top:simple-item == simple-value
top:array-item:0 == first
top:array-item:1 == second
Run Code Online (Sandbox Code Playgroud)

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

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

{
  "top": {
    "array-item": ["third"]
  }
}
Run Code Online (Sandbox Code Playgroud)

那一个变平了

top:array-item:0 == third
Run Code Online (Sandbox Code Playgroud)

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

top:simple-item == simple-value
top:array-item:0 == third
top:array-item:1 == second
Run Code Online (Sandbox Code Playgroud)

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

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

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

选项1:捏造阵列(不推荐)

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

{
  "components": [
    {
      "type": "Services.FirstProvider, Services",
      "services": [ ...]
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

通过在第二个"覆盖"配置中放置一个虚拟空元素,您可以稍微"捏造它":

{
  "components": [
    {
    },
    {
      "type": "Services.SecondProvider, Services",
      "services": [ ...]
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

而不是尝试组合两个JSON文件,只需IConfiguration通过单独加载JSON文件来创建两个单独的对象.分别在两个不同的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);
Run Code Online (Sandbox Code Playgroud)

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