如何将 appsettings.json 文件添加到我的 Azure 函数 3.0 配置中?



新的 Azure Function 3.0 SDK 提供了一种实现启动类的方法。它允许访问通过依赖注入可用的服务集合,我可以在其中添加自己的组件和第三方服务。

但是我不知道如何使用配置文件。

[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]
namespace MyNamespace
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
...

我的第三方服务将大型结构作为参数,这些配置文件是用二进制文件复制的。我可以将它们复制到appsettings.json文件的子部分中:

{
"MachineLearningConfig" : {
( about 50+ parameters and subsections )
}
}

配置值根据部署环境进行更新。为此,我使用 Azure DevOps 的文件转换任务:生产值不同于暂存和开发值。

根据文档 https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection 加载这些选项的方法是:

builder.Services.AddOptions<MachineLearningConfig>()
.Configure<IConfiguration>((settings, configuration) =>
{
configuration.GetSection("MachineLearningConfig").Bind(settings);
});

但这需要在主机环境中将所有设置添加为键/值字符串,而这正是我不想做的。它们太多了,这不像在 json 配置文件中那样容易维护。

我复制了那个appsettings.json和host.json

但是 Azure 函数 SDK 在启动时读取的 appsettings.json 文件不是我的应用程序的 appsettings.json,而是 Azure 函数工具的appsettings.json。因此configuration.GetSection("MachineLearningConfig")返回空值,因为 Azure 函数工具 bin 文件夹中没有appsettings.json文件。

所以,我的问题:如何从我的appsetting.json文件中读取我的MachineLearningConfig部分作为IOption<MachineLearningConfig>注入到我的应用程序中?

在 Azure Functions v3 中,可以将 ASP.NET-Core 中的appsettings.json配置模式与下面的ConfigureAppConfiguration调用一起使用(参考(。

此外,使用下面的Configure方法中的代码更改添加选项的方式。您不应该将IConfiguration传递给IServiceProvider.Configure<>()。这将允许您使用注入的IOptions<MachineLearningConfig>对象。

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.IO;
[assembly: FunctionsStartup(typeof(Startup))]
namespace MyAzureFunction
{
public class Startup : FunctionsStartup
{
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
var context = builder.GetContext();
builder.ConfigurationBuilder
.AddAppsettingsFile(context)
.AddAppsettingsFile(context, useEnvironment: true)
.AddEnvironmentVariables();
}
public override void Configure(IFunctionsHostBuilder builder)
{
if (builder == null) throw new ArgumentNullException(nameof(builder));
var configuration = builder.GetContext().Configuration;
builder.Services.Configure<MachineLearningConfig>(options =>
{
configuration.GetSection("MachineLearningConfig").bind(options);
});
}
}
public static class ConfigurationBuilderExtensions
{
public static IConfigurationBuilder AddAppsettingsFile(
this IConfigurationBuilder configurationBuilder,
FunctionsHostBuilderContext context,
bool useEnvironment = false
)
{
if (context == null) throw new ArgumentNullException(nameof(context));
var environmentSection = string.Empty;
if (useEnvironment)
{
environmentSection = $".{context.EnvironmentName}";
}
configurationBuilder.AddJsonFile(
path: Path.Combine(context.ApplicationRootPath, $"appsettings{environmentSection}.json"),
optional: true,
reloadOnChange: false);
return configurationBuilder;
}
}
}

Nkosi 的解决方案运行良好,但它确实通过替换 IConfiguration 单例:services.AddSingleton<IConfiguration>来更新 Azure 函数运行时为自己加载设置的方式。

我更喜欢另一个没有注入的IConfigurationRoot。我只需要注入链接到我自己的 IConfigurationRoot 的设置IOption<MachineLearningSettings>

我构建了另一个 IConfigurationRoot,它是 Startup 类的成员:

public class Startup : FunctionsStartup
{
private IConfigurationRoot _functionConfig = null;
private IConfigurationRoot FunctionConfig( string appDir ) => 
_functionConfig ??= new ConfigurationBuilder()
.AddJsonFile(Path.Combine(appDir, "appsettings.json"), optional: true, reloadOnChange: true)
.Build();
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddOptions<MachineLearningSettings>()
.Configure<IOptions<ExecutionContextOptions>>((mlSettings, exeContext) =>
FunctionConfig(exeContext.Value.AppDirectory).GetSection("MachineLearningSettings").Bind(mlSettings) );
}
}

注意:连接字符串必须保留在应用程序设置中,因为触发器需要它来创建未启动的函数应用的实例(在消耗服务计划中(。

使用此.NET Core 3.1Azure Function 3。花了几个小时天。这是我想到的。

[assembly: FunctionsStartup(typeof(Ugly.AzureFunctions.Startup))]
namespace Ugly.AzureFunctions
{
class Startup : FunctionsStartup
{
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
try
{
// On Azure, we need to get where the app is.
// If you use Directory.GetCurrentDirectory(), you will get something like D:Program Files (x86)SiteExtensionsFunctions3.0.1478532bit
var basePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "..");
var environmentName = builder.GetContext().EnvironmentName;
builder.ConfigurationBuilder
.SetBasePath(basePath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{environmentName}.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
}
catch (Exception ex)
{
// Handle exceptions about this. Which __should__ never ever happen.
// The previous comment is sarcastic.
throw;
}
}
public override void Configure(IFunctionsHostBuilder builder)
{
try
{
// DO NOT add the configuration as Singleton.
// If you need the IConfiguration:
//var configuration = builder.GetContext().Configuration;
builder.Services
.AddOptions<MachineLearningConfig>()
.Configure<IConfiguration>((settings, configuration) => {
configuration.GetSection("MachineLearningConfig").Bind(settings);
});
}
catch (Exception ex)
{
// Handle or not handle? That's the question.
throw;
}
}
}
}

在启动类中:

IConfigurationRoot config = new ConfigurationBuilder()
.SetBasePath(Environment.CurrentDirectory)
.AddJsonFile("someSettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();

将 json 文件添加到包含设置的项目。请注意,local.settings.json 在部署过程中会被忽略/删除。(将文件命名为其他名称。

MS 文档已使用配置示例进行了更新

请记住安装先决条件部分中列出的必需库。

using System.IO;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(MyNamespace.Startup))]
namespace MyNamespace
{
public class Startup : FunctionsStartup
{
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
FunctionsHostBuilderContext context = builder.GetContext();
builder.ConfigurationBuilder
.AddJsonFile(Path.Combine(context.ApplicationRootPath, "appsettings.json"), optional: true, reloadOnChange: false)
.AddJsonFile(Path.Combine(context.ApplicationRootPath, $"appsettings.{context.EnvironmentName}.json"), optional: true, reloadOnChange: false)
.AddEnvironmentVariables();
}
}
}

经过一番研究,我在 Githib 上遇到了这个线程

在函数应用中使用 appsettings.json + IConfiguration

我根据显示有效的评论和建议制作了以下扩展。

public static class FunctionHostBuilderExtensions {
/// <summary>
/// Set up the configuration for the builder itself. This replaces the 
/// currently registered configuration with additional custom configuration.
/// This can be called multiple times and the results will be additive.
/// </summary>
public static IFunctionsHostBuilder ConfigureHostConfiguration (
this IFunctionsHostBuilder builder, 
Action<IServiceProvider, IConfigurationBuilder> configureDelegate) {
IServiceCollection services = builder.Services;            
var providers = new List<IConfigurationProvider>();            
//Cache all current configuration provider
foreach (var descriptor in services.Where(d => d.ServiceType == typeof(IConfiguration)).ToList()) {
var existingConfiguration = descriptor.ImplementationInstance as IConfigurationRoot;
if (existingConfiguration is null) {
continue;
}
providers.AddRange(existingConfiguration.Providers);
services.Remove(descriptor);
}
//add new configuration based on original and newly added configuration
services.AddSingleton<IConfiguration>(sp => {
var configurationBuilder = new ConfigurationBuilder();                    
//call custom configuration
configureDelegate?.Invoke(sp, configurationBuilder);                
providers.AddRange(configurationBuilder.Build().Providers);                
return new ConfigurationRoot(providers);
});            
return builder;
}
}

主要思想是提取所有当前注册的配置相关类型,创建新的构建器,应用自定义配置并构建新配置,并将原始和自定义配置详细信息合并为一个。

然后它将用于Startup

public class Startup : FunctionsStartup {
public override void Configure(IFunctionsHostBuilder builder) {
builder.ConfigureHostConfiguration((sp, config) => {
var executioncontextoptions = sp.GetService<IOptions<ExecutionContextOptions>>().Value;
var currentDirectory = executioncontextoptions.AppDirectory;
config
.SetBasePath(currentDirectory)
.AddJsonFile("appSettings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
//if there are multiple settings files, consider extracting the list,
//enumerating it and adding them to the configuration builder.
});
builder.Services
.AddOptions<MachineLearningConfig>()
.Configure<IConfiguration>((settings, configuration) => {
configuration.GetSection("MachineLearningConfig").Bind(settings);
});
}
}

以上内容现在应该能够从自定义配置中获取设置。

在本地开发函数应用时,必须在local.settings.json项目文件中维护这些值的本地副本。若要了解详细信息,请参阅Local settings文件。

将所需设置上传到 Azure 中的函数应用的最简单方法是使用成功发布项目后显示的"管理Application Settings..."链接。

请参阅此example,了解如何获取这些设置值。

var config = new ConfigurationBuilder()
.SetBasePath(currentDirectory)
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();

这是一个sample project

最新更新