在 FunctionsStartup 中使用 ConfigurationBuilder

Pau*_*els 7 azure azure-functions

我有一个 Azure 函数,我正在使用 DI 系统来注册一些类型;例如:

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services
            .AddTransient<IMyInterface, MyClass>()
    . . . etc
Run Code Online (Sandbox Code Playgroud)

但是,我还要从我的环境设置中注册一些数据。在函数本身内部,我可以获得ExecutionContext, 所以我可以这样做:

IConfiguration config = new ConfigurationBuilder()
   .SetBasePath(context.FunctionAppDirectory)
   .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
   .AddEnvironmentVariables()
   .Build();
Run Code Online (Sandbox Code Playgroud)

但是,在 FunctionsStartup 中,我无权访问ExecutionContext. 有没有一种方法可以从 FunctionsStartup 类中获取 ExecutionContext ,或者另一种确定当前运行目录的方法,以便我可以设置基本路径?

Ter*_*lla 17

虽然对这个问题的检查答案是正确的,但我认为它缺乏关于原因的深度。您应该知道的第一件事是,在幕后,Azure 函数使用与ASP.NET Core 应用程序中相同的ConfigurationBuilder,但具有不同的提供程序集。与 ASP.NET Core 的文档(https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/)不同,Azure Functions 并非如此。

要了解这组提供程序,您可以将以下代码行放入FunctionStartup类的Configure(IFunctionsHostBuilder builder)方法中,

var configuration = builder.Services.BuildServiceProvider().GetService<IConfiguration>();
Run Code Online (Sandbox Code Playgroud)

在命令后放置一个调试断点,在调试模式下执行您的函数并在配置变量上执行快速观察...(右键单击变量名称以选择快速观察...)。

深入代码执行的结果是以下提供程序列表。

Microsoft.Extensions.Configuration.ChainedConfigurationProvider
MemoryConfigurationProvider
HostJsonFileConfigurationProvider
JsonConfigurationProvider for 'appsettings.json' (Optional)
EnvironmentVariablesConfigurationProvider
MemoryConfigurationProvider
Run Code Online (Sandbox Code Playgroud)

所述ChainedConfigurationProvider增加了一个现有IConfiguration作为源。在默认配置情况下,添加主机配置并将其设置为应用程序配置的第一个源。

第一个MemoryConfigurationProvider添加键/值{[AzureWebJobsConfigurationSection, AzureFunctionsJobHost]}。至少它在开发环境中是这样做的。在我写这篇文章的时候,我找不到关于这个MemoryConfigurationProviderAzureWebJobsConfigurationSection目的的文档。

HostJsonFileConfigurationProvider是那些在幕后无证供应商的另外一个,但是在看的文件host.jsonhttps://docs.microsoft.com/en-us/azure/azure-functions/functions-host-json)它似乎负责提取此元数据。

JsonConfigurationProviderappsettings.json似乎是一个明显的相关性,以ASP.NET核心的使用appsettings.json除了一件事是这是行不通的。经过一番调查,我发现Source FileProvider Root没有设置为文件所在的应用程序根文件夹,而是一些模糊的 AppData 文件夹(C:\Users%USERNANE%\AppData\Local\AzureFunctionsTools\Releases\3.15.0\ cli_x64)。 去钓鱼。

EnvironmentVariablesConfigurationProvider负载环境变量的键值对。

第二个MemoryConfigurationProvider添加键/值{[AzureFunctionsJobHost:logging:console:isEnabled, false]}。至少它在开发环境中是这样做的。同样,在我写这篇文章的时候,我找不到关于这个MemoryConfigurationProviderAzureFunctionsJobHost目的的文档。

现在需要指出的有趣的事情是配置中没有任何地方提到local.settings.json。那是因为local.settings.json不是ConfigurationBuilder进程的一部分。而local.settings.json是 Azure Functions Core Tools 的一部分,它允许您在本地计算机上开发和测试您的函数 ( https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-本地)。Azure 函数核心工具仅关注文档中定义的特定部分和键/值,如IsEncryptedValuesConnectionString部分等(https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local#local-settings-file)。这些键/值发生的事情也是独一无二的。例如,部分中的键/值作为变量插入到环境中。大多数开发人员甚至没有注意到 local.settings.json 默认设置为被 Git 忽略,如果您从开发环境中删除存储库只是为了在将来恢复它,这也会导致问题。ASP.NET Core 已使用应用程序机密 ( https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets )修复的某些内容。

那么,如果我们按照原始问题中的建议使用ConfigurationBuilder创建我们自己的配置会发生什么

IConfiguration config = new ConfigurationBuilder()
   .SetBasePath(context.FunctionAppDirectory)
   .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
   .AddEnvironmentVariables()
   .Build();
Run Code Online (Sandbox Code Playgroud)

或使用其他答案之一中显示的示例?

ExecutionContextOptions executionContextOptions = builder.Services.BuildServiceProvider().GetService<IOptions<ExecutionContextOptions>>().Value;

IConfigurationBuilder configurationBuilder = new ConfigurationBuilder()
    .SetBasePath(executionContextOptions.AppDirectory)
    .AddEnvironmentVariables()
    .AddJsonFile("appsettings.json", false)
    .AddJsonFile("local.settings.json", true)
    .AddUserSecrets(Assembly.GetExecutingAssembly(), true);
Run Code Online (Sandbox Code Playgroud)

以下只是这两个示例的一些问题。

  • 第二个示例的顺序不正确,因为 AddEnvironmentVariables 应该放在最后。

  • 这两个示例都没有提到需要以下代码行。项目清单

    builder.Services.AddSingleton<IConfiguration>(configurationBuilder.Build());

    如果没有这一行,则配置仅存在于FunctionStartup类的Configure(IFunctionsHostBuilder builder)方法中。但是,使用该行替换 Azure Function 内部构建的配置。这不一定是一件好事,因为您无法替换HostJsonFileConfigurationProvider 之类的提供程序。

  • 读取local.settings.json文件(.AddJsonFile("appsettings.json"))不会像预期的那样将Values部分中的键/值对作为单独的键/值对放入配置中,而是将它们分组在Values 下部分。换句话说,例如,如果你想获得{[“AzureWebJobsStorage”:“”]},你可以使用命令configuration.GetValue(“值:AzureWebJobsStorage”) 。问题是 Azure 期望通过键名"AzureWebJobsStorage"访问它。更有趣的是,因为local.settings。这是多余的,因为 Azure Functions Core Tools 已经将这些值放入环境中。这将做的唯一一件事是允许您访问未定义为local.settings.json ( https://docs.microsoft.com/en-us/azure/azure-functions/functions-run -local#local-settings-file)。但是为什么要从不会复制到生产代码中的文件中提取配置值呢?

所有这些都为我们提供了一种更好的方法来影响对配置的更改,而不会破坏 Azure Function 的默认配置构建,即覆盖FunctionStartup类中的ConfigureAppConfiguration方法( https://docs.microsoft.com/en-us/ azure/azure-functions/functions-dotnet-dependency-injection#customizing-configuration-sources)。

以下示例通过添加用户机密使文档中提供的示例更进一步。

public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
    FunctionsHostBuilderContext context = builder.GetContext();

    builder.ConfigurationBuilder
        .SetBasePath(context.ApplicationRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
        .AddJsonFile($"appsettings.{context.EnvironmentName}.json", optional: true, reloadOnChange: false)
        .AddUserSecrets(Assembly.GetExecutingAssembly(), true, true)
        .AddEnvironmentVariables();
}
Run Code Online (Sandbox Code Playgroud)

默认情况下,appsettings.json等配置文件不会自动复制到 Azure Function 输出文件夹。请务必查看文档 ( https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection#customizing-configuration-sources ) 以了解对.csproj文件的修改。另请注意,由于该方法附加现有提供程序的方式,必须始终以.AddEnvironmentVariables()结尾。

  • 这是我能找到的唯一答案,它描述了本地开发(Azure Functions Core Tools)和生产环境之间实际发生的情况。 (3认同)

sil*_*ent 5

Azure Functions (v2) 中不需要任何配置对象。所有应用程序设置都作为环境变量注入。所以你可以做一个简单的Environment.GetEnvironmentVariable()

在本地运行时local.settings.json,以相同的方式读取。

请参阅此处:https : //docs.microsoft.com/en-us/sandbox/functions-recipes/environment-variables?tabs=csharp