Azure Functions,如何拥有多个 .json 配置文件
Azure Functions, how to have multiple .json config files
所以我编写了一个在本地运行良好的 azure 函数。我相信这取决于 local.setting.json
文件。但是当我将它发布到 azure 时,该功能不起作用,因为它找不到我定义的设置值。来自 Web 应用程序和控制台驱动的方法,我们将拥有与每个环境关联的不同配置文件。我怎样才能让它工作,这样我就可以拥有多个 settings.json
文件,例如一个用于 dev、stag 和 prod 环境?最终结果是使用 octopus deploy 进行部署,但此时,如果我什至无法使用 publish 进行部署,那么就没有机会这样做了。
我很困惑为什么这些信息不容易获得,因为假设这是一件很常见的事情?
此文档有 description 关于 local.settings.json
:
By default, these settings are not migrated automatically when the
project is published to Azure.
一种方法是使用 --publish-local-settings
:
Publish settings in local.settings.json to Azure, prompting to
overwrite if the setting already exists.
另一种方法是使用Manage Application Settings
,Remote是Azure函数应用程序中的当前设置。或者选择添加设置以创建新的应用程序设置。详情可以参考这个文档:Function app settings.
我希望看到功能以与 asp.net 核心或控制台应用程序相同的方式支持环境特定设置。与此同时,我正在使用下面的代码,这有点老套(见评论)。
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
// Get the path to the folder that has appsettings.json and other files.
// Note that there is a better way to get this path: ExecutionContext.FunctionAppDirectory when running inside a function. But we don't have access to the ExecutionContext here.
// Functions team should improve this in future. It will hopefully expose FunctionAppDirectory through some other way or env variable.
string basePath = IsDevelopmentEnvironment() ?
Environment.GetEnvironmentVariable("AzureWebJobsScriptRoot") :
$"{Environment.GetEnvironmentVariable("HOME")}\site\wwwroot";
var config = new ConfigurationBuilder()
.SetBasePath(basePath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false) // common settings go here.
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT")}.json", optional: false, reloadOnChange: false) // environment specific settings go here
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: false) // secrets go here. This file is excluded from source control.
.AddEnvironmentVariables()
.Build();
builder.Services.AddSingleton<IConfiguration>(config);
}
public bool IsDevelopmentEnvironment()
{
return "Development".Equals(Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT"), StringComparison.OrdinalIgnoreCase);
}
}
好的,我现在可以使用了:) 因为我们使用章鱼部署,所以我们不需要多个配置文件,所以我们只有一个 appsettings.Release.json 文件也根据正在部署的环境获取替换的值。
主要功能代码如下。
public static class Function
{
// Format in a CRON Expression e.g. {second} {minute} {hour} {day} {month} {day-of-week}
// https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer
// [TimerTrigger("0 59 23 * * *") = 11:59pm
[FunctionName("Function")]
public static void Run([TimerTrigger("0 59 23 * * *")]TimerInfo myTimer, ILogger log)
{
// If running in debug then we dont want to load the appsettings.json file, this has its variables substituted in octopus
// Running locally will use the local.settings.json file instead
#if DEBUG
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
#else
IConfiguration config = Utils.GetSettingsFromReleaseFile();
#endif
// Initialise dependency injections
var serviceProvider = Bootstrap.ConfigureServices(log4Net, config);
var retryCount = Convert.ToInt32(config["RetryCount"]);
int count = 0;
while (count < retryCount)
{
count++;
try
{
var business = serviceProvider.GetService<IBusiness>();
business.UpdateStatusAndLiability();
return;
}
catch (Exception e)
{
// Log your error
}
}
}
}
Utils.cs 文件如下所示
public static class Utils
{
public static string LoadSettingsFromFile(string environmentName)
{
var executableLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
// We need to go back up one level as the appseetings.Release.json file is not put in the bin directory
var actualPathToConfig = Path.Combine(executableLocation, $"..\appsettings.{environmentName}.json");
using (StreamReader reader = new StreamReader(actualPathToConfig))
{
return reader.ReadToEnd();
}
}
public static IConfiguration GetSettingsFromReleaseFile()
{
var json = Utils.LoadSettingsFromFile("Release");
var memoryFileProvider = new InMemoryFileProvider(json);
var config = new ConfigurationBuilder()
.AddJsonFile(memoryFileProvider, "appsettings.json", false, false)
.Build();
return config;
}
}
appsettings.Release.json 设置为 Content 和 Copy Always visual studio。看起来像这样
{
"RetryCount": "#{WagonStatusAndLiabilityRetryCount}",
"RetryWaitInSeconds": "#{WagonStatusAndLiabilityRetryWaitInSeconds}",
"DefaultConnection": "#{YourConnectionString}"
}
实际上,我相信您可以在那里已经有一个 appsettings.config 文件并跳过 appsettings.Release.json 文件,但这是有效的,您现在可以用它做任何您想做的事。
所以我编写了一个在本地运行良好的 azure 函数。我相信这取决于 local.setting.json
文件。但是当我将它发布到 azure 时,该功能不起作用,因为它找不到我定义的设置值。来自 Web 应用程序和控制台驱动的方法,我们将拥有与每个环境关联的不同配置文件。我怎样才能让它工作,这样我就可以拥有多个 settings.json
文件,例如一个用于 dev、stag 和 prod 环境?最终结果是使用 octopus deploy 进行部署,但此时,如果我什至无法使用 publish 进行部署,那么就没有机会这样做了。
我很困惑为什么这些信息不容易获得,因为假设这是一件很常见的事情?
此文档有 description 关于 local.settings.json
:
By default, these settings are not migrated automatically when the project is published to Azure.
一种方法是使用 --publish-local-settings
:
Publish settings in local.settings.json to Azure, prompting to overwrite if the setting already exists.
另一种方法是使用Manage Application Settings
,Remote是Azure函数应用程序中的当前设置。或者选择添加设置以创建新的应用程序设置。详情可以参考这个文档:Function app settings.
我希望看到功能以与 asp.net 核心或控制台应用程序相同的方式支持环境特定设置。与此同时,我正在使用下面的代码,这有点老套(见评论)。
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
// Get the path to the folder that has appsettings.json and other files.
// Note that there is a better way to get this path: ExecutionContext.FunctionAppDirectory when running inside a function. But we don't have access to the ExecutionContext here.
// Functions team should improve this in future. It will hopefully expose FunctionAppDirectory through some other way or env variable.
string basePath = IsDevelopmentEnvironment() ?
Environment.GetEnvironmentVariable("AzureWebJobsScriptRoot") :
$"{Environment.GetEnvironmentVariable("HOME")}\site\wwwroot";
var config = new ConfigurationBuilder()
.SetBasePath(basePath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: false) // common settings go here.
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT")}.json", optional: false, reloadOnChange: false) // environment specific settings go here
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: false) // secrets go here. This file is excluded from source control.
.AddEnvironmentVariables()
.Build();
builder.Services.AddSingleton<IConfiguration>(config);
}
public bool IsDevelopmentEnvironment()
{
return "Development".Equals(Environment.GetEnvironmentVariable("AZURE_FUNCTIONS_ENVIRONMENT"), StringComparison.OrdinalIgnoreCase);
}
}
好的,我现在可以使用了:) 因为我们使用章鱼部署,所以我们不需要多个配置文件,所以我们只有一个 appsettings.Release.json 文件也根据正在部署的环境获取替换的值。
主要功能代码如下。
public static class Function
{
// Format in a CRON Expression e.g. {second} {minute} {hour} {day} {month} {day-of-week}
// https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-timer
// [TimerTrigger("0 59 23 * * *") = 11:59pm
[FunctionName("Function")]
public static void Run([TimerTrigger("0 59 23 * * *")]TimerInfo myTimer, ILogger log)
{
// If running in debug then we dont want to load the appsettings.json file, this has its variables substituted in octopus
// Running locally will use the local.settings.json file instead
#if DEBUG
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
#else
IConfiguration config = Utils.GetSettingsFromReleaseFile();
#endif
// Initialise dependency injections
var serviceProvider = Bootstrap.ConfigureServices(log4Net, config);
var retryCount = Convert.ToInt32(config["RetryCount"]);
int count = 0;
while (count < retryCount)
{
count++;
try
{
var business = serviceProvider.GetService<IBusiness>();
business.UpdateStatusAndLiability();
return;
}
catch (Exception e)
{
// Log your error
}
}
}
}
Utils.cs 文件如下所示
public static class Utils
{
public static string LoadSettingsFromFile(string environmentName)
{
var executableLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
// We need to go back up one level as the appseetings.Release.json file is not put in the bin directory
var actualPathToConfig = Path.Combine(executableLocation, $"..\appsettings.{environmentName}.json");
using (StreamReader reader = new StreamReader(actualPathToConfig))
{
return reader.ReadToEnd();
}
}
public static IConfiguration GetSettingsFromReleaseFile()
{
var json = Utils.LoadSettingsFromFile("Release");
var memoryFileProvider = new InMemoryFileProvider(json);
var config = new ConfigurationBuilder()
.AddJsonFile(memoryFileProvider, "appsettings.json", false, false)
.Build();
return config;
}
}
appsettings.Release.json 设置为 Content 和 Copy Always visual studio。看起来像这样
{
"RetryCount": "#{WagonStatusAndLiabilityRetryCount}",
"RetryWaitInSeconds": "#{WagonStatusAndLiabilityRetryWaitInSeconds}",
"DefaultConnection": "#{YourConnectionString}"
}
实际上,我相信您可以在那里已经有一个 appsettings.config 文件并跳过 appsettings.Release.json 文件,但这是有效的,您现在可以用它做任何您想做的事。