It looks like a Hybrid of Jason and Oneil/Liam is correct.
From what I can tell, in the name/declaration/definition of the function it has to come from the local.settings.json when developing and referred to like "%TheQueueName%", and then entered in Function Configuration -> Application Settings for Azure.
In the actual function itself, you can leverage json file injection via Startup.cs and then include the values in the function itself.
This deserves a totally separate blog post (and there have been similar, yet not quite as sophisticated setups mentioned, but here is what I've done and figured out after a year plus and works fantastically.
Files setup:
- I have a Config folder in the Functions project which stores xyz.settings.json files. The files here are set to Content, and then to Build and also Publish in the .csproj file.
- In the Config folder I also have a secrets.json file which I store all the secrets I do not want published. This is set to build only, not publish! Each xyz.settings.json file has a value of "--SECRET--" for values that I want secret.
- local.settings.json has the value pairs for "Values" which is used for dev. This is also for build only. These values are then added to the Function portal in Azure for the published app. These values are only used for the function name/declaration/definition.
- I have created a class that corresponds to the values in the xyz.settings.json file. This allows you the benefit of accessing the values by injection. Also, in the Function Application Settings you can refer to these values by XyzSettings:Value when entering a secret value.
Configuration Setup: Startup.cs
(even though it says /home/site/wwwroot - the files are based off of the root of the project, when published that will be the root)
public override void Configure(IFunctionsHostBuilder builder)
{
var currentDirectory = "/home/site/wwwroot";
var config = new ConfigurationBuilder()
.SetBasePath(currentDirectory)
.AddJsonFile("local.settings.json", optional: false, reloadOnChange: true)
.AddJsonFile("Config/xyz.settings.json", optional: false, reloadOnChange: true)
.AddJsonFile("Config/xyz.settings.dev.json", optional: true, reloadOnChange: true)
.AddJsonFile("Config/secret.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
builder.Services.Configure<XyzSettings>(config.GetSection("XyzSettings"));
What this does and how it works:
- Application settings are applied in a very specific order, with the json files applying in the order that they are added. If there are duplicate settings, the existing files are overwritten.
- I have local.settings first. Then followed by general json files (xyz.settings.json), followed by environmental specific variants (zyx.settings.dev.json), followed by secrets.json
- Environmental specific variables go last (these are either what you specify on your machine - or the equivalent are the Function Application Settings)
- This approach allows you to have a really nice and stable set of settings. This is especially useful if you have a project that has many different integrations, apis, etc. They can all be different files.
- Notice how the last two json files are marked as optional. They have to be since they are not included when published. Any json files that are required and are not included will cause the function to fail.
Speaking of Secrets:
Local Secrets can be stored in the secrets.json as long as they are not set to publish.
In Azure, it is recommended to store the values in Function App Settings which reach out to Azure Key Vault.
It is brilliant how it is configured. All you do in the Function App Settings is to name the variable what it is in settings, like XyzSettings:SettingName and then refer to the location in Key Vault like follows:
@Microsoft.KeyVault(SecretUri=https://yourvalutname.vault.azure.net/secrets/secret-name/auto-generated-keyvaultguid)
Function File:
(using a Queues trigger as an example but operates the same way)
namespace Xyz.Functions
{
public class Azure_Queue_Add_Xyz
{
private readonly XyzSettings _xyzSettings = null;
public Azure_Queue_Add_Xyz(IOptions<AzureSettings> azure_settings)
{
_azureSettings = azure_settings.Value;
}
[FunctionName("Azure_Queue_Add_Xyz")]
public void Run(
[HttpTrigger(AuthorizationLevel.Function, "post",
Route = "HttpTrigger/Azure_Queue_Add_Xyz")] xyzConfig input,
[Queue("%TheQueueName%"), StorageAccount("StorageAccount")] ICollector<string> msgOutput,
ILogger logger,
ExecutionContext context)
{
logger.LogError("{0} is processing a request", context.FunctionName);
logger.LogError("{0} - Queue: {1}", context.FunctionName, _xyzSettings.TheQueueName);
logger.LogError("{0} - CloudQueueMessage: {1}", context.FunctionName, JsonConvert.SerializeObject(input));
msgOutput.Add(JsonConvert.SerializeObject(input));
}
}
}