将复杂结构与 AddEnvironmentVariables 一起使用

Using complex structures with AddEnvironmentVariables

问题

如何在使用 ConfigurationBuilderAddEnvironmentVariables 方法设置配置时处理复杂的结构,例如数组。

即调用什么环境变量来表示以下结构?

{
    "MyApp": {
        "SendAlertsTo": [
            {"Name": "Joe Blogger", "Email": "JoeBlogger@example.com"},
            {"Name": "Jane Doer", "Email": "JaneDoer@example.com"}
        ]
    }
}

带上下文的详细版本

我们正在编写将在容器中托管的应用程序。最初我们继续使用 AppSettings.json 文件来保存设置,在启动时通过 entrypoint.sh shell 脚本从环境变量填充此文件的内容。

后来我们意识到我们可以使用ConfigurationBuilderAddEnvironmentVariables方法直接从环境变量中提取值,从而避免维护entrypoint.sh脚本的开销作为每次添加新设置时更新的另一个地方。

这适用于应用程序设置文件,例如:

{
    "MyApp": {
        "SmtpServer": "smtp.example.com",
        "FromAddress": "JoeyBlogger@example.com"
    },
    "Logging": {
        "LogLevel": "Default"
    }
}

.. 因为这简单地转化为:

export MyApp:SmtpServer=smtp.example.com
export MyApp:FromAddress=JoeyBlogger@example.com
export Logging:LogLevel=Default

但是,我最近看到一个开发人员的应用程序设置文件,用于一些新的监控,如下所示(注意;这不是我们托管环境中使用的实际设置;它只是触发此问题的示例).在这种情况下,使用上述方法效果不佳,因为名称为 Serilog:WriteTo:Name 的两个不同设置以及以 Serilog:WriteTo:Args:* 开头的任何条目都与哪个条目相关的歧义。

{
  "Serilog"
    "WriteTo": [
      {
        "Name": "Async",
        "Args": {
          "configure": [
            {
              "Name": "File",
              "Args": {
                "path": ".\log.txt",
                "rollingInterval": "Day",
                "retainedFileCountLimit": 7,
                "buffered": true
              }
            }
          ]
        }
      },
      {
        "Name": "Async",
        "Args": {
          "configure": [
            {
              "Name": "Console"
            }
          ]
        }
      }
    ]
  }
}

我猜我们会通过某种索引来处理这个问题;但我无法在文档中找到任何关于此的内容。

export Serilog:WriteTo[0]:Name=Async
export Serilog:WriteTo[0]:Args:configure[0]:Name=File
export Serilog:WriteTo[0]:Args:configure[0]:Args:path=.\log.txt
export Serilog:WriteTo[0]:Args:configure[0]:Args:rollingInterval=Day
export Serilog:WriteTo[0]:Args:configure[0]:Args:retainedFileCountLimit=7
export Serilog:WriteTo[0]:Args:configure[0]:Args:buffered=true
export Serilog:WriteTo[1]:Name=Async
export Serilog:WriteTo[1]:Args:configure[0]:Name=Console

但是,运行 一个快速的 PoC 表明上述方法不起作用。如何做到这一点?

我在这里找到了解决方案:MS Extensions Configuration Deep Dive

答案是使用索引,但索引号被当作命名元素处理;即

{
    "MyApp": {
        "SendAlertsTo": [
            {"Name": "Joe Blogger", "Email": "JoeBlogger@example.com"},
            {"Name": "Jane Doer", "Email": "JaneDoer@example.com"}
        ]
    }
}

变为:

export MyApp:SendAlertsTo:0:Name=Joe Blogger
export MyApp:SendAlertsTo:0:Email=JoeBlogger@example.com
export MyApp:SendAlertsTo:1:Name=Jane Doer
export MyApp:SendAlertsTo:1:Email=JaneDoer@example.com

此外,对于 Linux 托管还有一点我不知道/与数组问题无关.. : 分隔符应该是 __,所以上面变成:

export MyApp__SendAlertsTo__0__Name=Joe Blogger
export MyApp__SendAlertsTo__0__Email=JoeBlogger@example.com
export MyApp__SendAlertsTo__1__Name=Jane Doer
export MyApp__SendAlertsTo__1__Email=JaneDoer@example.com