Im working with Azure functions and have a problem.
I declared a local.settings.json file with my variables as follows:
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"TopicEndpoint": "my endpoint"
}
}
This allows my azure function to read the settings using:
var config = new ConfigurationBuilder()
.SetBasePath(context.FunctionAppDirectory)
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
var myTopic = config["Values:TopicEndpoint"];
This allows me to publish and export my variables to the portal via:
func azure functionapp
publish myfunctionapp --publish-local-settings -i
However, upon publishing and verifying that the value is in the 'Application Settings' in the portal, the "Values:TopicEndpoint" doesn't exist.
In order to be able to access its value i have to put my variables directly under the json root:
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
}
"TopicEndpoint": "my endpoint"
}
That way I can safely use config['TopicEndpoint'] both in my local development environment, as well as on Azure. However, this defeats the purpose of the --publish-local-settings -i as it only exports the values found under the 'Values' key, so I have to create all my settings manually.
Do you know why this happens or if maybe Im missing something?
I guess you use it a bit in a different way it should be. The thing is that the values from the local.settings.json come as environment variables automatically, so you don't have to worry about working with the file at all. That's how we do it on our project and it works on all environments.
// see, just env variables
var configuration = new ConfigurationBuilder().AddEnvironmentVariables().Build();
// and then use
var value = configuration["TopicEndpoint"];
I found the issue.
The problem was that I was adding a separate secret.settings.json as suggested here
https://www.tomfaltesek.com/azure-functions-local-settings-json-and-source-control/
Therefore I was loading my configurations like this:
var config = new ConfigurationBuilder()
.SetBasePath(context.FunctionAppDirectory)
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddJsonFile("secret.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
My local settings file looked like this:
{
"Values": {
"TopicEndpoint": "my endpoint"
}
}
And my secret settings like this:
{
"Values": {
"TopicKey": "my key"
}
}
This caused a conflict so I needed to remove the 'Values' key from the secret.settings.json so that it looked like this:
{
"TopicKey": "my key"
}
This way I am able to both use func azure functionapp publish myfunctionapp --publish-local-settings -i to deploy the values inside my local settings file and use both files as environment variables.
Related
I am using an appsettings files in my Azure Function using a Startup class. In my appsettings files, there are keyvault references. But I cant seem to get it to work as the keyvault references never get replaced by actual strings from the keyvault. What am I doing wrong? My sample uses a client id and secret since I needed to test locally but will get switched out to using the managed identity in Prod.
Startup has following function:
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
try
{
FunctionsHostBuilderContext context = builder.GetContext();
var configurationBuilder = builder.ConfigurationBuilder
.SetBasePath(context.ApplicationRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
builder.ConfigurationBuilder
.SetBasePath(context.ApplicationRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.AddAzureKeyVault(configurationBuilder["vaultUri"], "<clientid>", "<clientsecret>");
} catch (Exception e)
{
throw new Exception(e.StackTrace + " " + e.Message);
}
}
However the configuration object still has the keyvault reference strings even after using the "AddAzureKeyVault" method. What am I doing wrong?
My appsettings file looks like this
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
},
"MySection": {
"MyUrl": "#Microsoft.KeyVault(SecretUri=https://mykv.vault.azure.net/secrets/MySection-MyUrl/)"
},
"vaultUri": "https://mykv.vault.azure.net/"
}
Shouldnt the MyUrl key get updated with actual values from the keyvault?
UPDATE: So I realized I was using the wrong nuget pacakge for Keyvault. So instead switched to Azure.Extensions.AspNetCore.Configuration.Secrets. Code is now changed to using Managed Identity. But somehow the values still dont update :(
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
try
{
FunctionsHostBuilderContext context = builder.GetContext();
var configurationBuilder = builder.ConfigurationBuilder
.SetBasePath(context.ApplicationRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
string userAssignedClientId = configurationBuilder["userAssignedClientId"];
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { ManagedIdentityClientId = userAssignedClientId });
var options = new AzureKeyVaultConfigurationOptions { ReloadInterval = TimeSpan.FromHours(24) };
builder.ConfigurationBuilder
.SetBasePath(context.ApplicationRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
.AddAzureKeyVault(new Uri(configurationBuilder["vaultUri"]), credential, options)
.Build();
} catch (Exception e)
{
throw new Exception(e.StackTrace + " " + e.Message);
}
}
This is because you are:
Not using app setting keyvault references correctly -- they must be set in your App Service's app configuration section, not in a configuration file.
Trying to combine app settings references with direct application keyvault integration. You only need one of the two, not both.
Basically, remove this:
"MySection": {
"MyUrl": "#Microsoft.KeyVault(SecretUri=https://mykv.vault.azure.net/secrets/MySection-MyUrl/)"
}
It's not loading the secret from keyvault because you're already defining the value.
Also, for what it's worth, this code is not doing anything useful and should be removed:
catch (Exception e)
{
throw new Exception(e.StackTrace + " " + e.Message);
}
The exception you're catching already has a stack trace and message. You're not accomplishing anything slightly reformatting the contents and throwing a new exception.
I am working on an Azure SignalR application and everything is working fine on my local machine when I set the following section in my appsettings.json:
"Azure": {
"SignalR": {
"ConnectionString": "XXXXX"
}
}
And then initialize in my startup.cs as follows:
services.AddSignalR().AddAzureSignalR();
However when I create the same environment variable in my Azure App Service using App Service>Configration>ApplicationSettings:
My application is unable to start and I get the following application error:
System.ArgumentException: Connection string missing required properties endpoint and accesskey. (Parameter 'connectionString')
at Microsoft.Azure.SignalR.ConnectionStringParser.Parse(String connectionString)
at Microsoft.Azure.SignalR.ServiceEndpoint..ctor(String connectionString, EndpointType type, String name)
When I hardcore my connection string onto the AddAzureSignalR() connectionstring parameter and deploy everything works fine.
It would seem that azuresignalR is unable to pickup this environment variable, despite also being able to see it via the Kudo Appsettings page as Azure:SginalR:ConnectionString.
You need to initiate like this,
string azureSignalrConnectionString = configuration["Azure:SignalR:ConnectionString"];
services.AddSignalR().AddNewtonsoftJsonProtocol().AddAzureSignalR(options =>
{
options.ConnectionString = azureSignalrConnectionString;
});
So I asked this same question on the Azure SignalR github page and below was the answer I got:
EnvironmentVariablesConfigurationProvider automatically replaces __
with : . So when you configures connection string via environment
variables, you should use Azure__SignalR__ConnectionString as the key.
When you configures it via JSON file, you should use the origin key
Azure:SignalR:ConnectionString.
Once I changed it to the double underscores all worked
For net core 5, use:
string azureSignalrConnectionString = Configuration["Azure:SignalR:ConnectionString"];
services.AddSignalR()
.AddAzureSignalR(options =>
{
options.ConnectionString = azureSignalrConnectionString;
});
appsettings.json, like:
{
"Azure": {
"SignalR": {
"ConnectionString": "<your-connection-string>"
}
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
process.env variable showing undefined while running yarn run jest. I have stored every config variables in my local.settings.json file, and it is working perfectly in normal debug.
My code is like this:
local.settings.json:
{
"IsEncrypted": false,
"Host": {
"LocalHttpPort": 7071,
"CORS": "*"
},
"Values": {
"IOTHUB_CONNECTION_STRING": "xxxxxxxxxxxxxxxxxx",
"AZURE_DEVOPS_URL": "xxxxxxxxxxxxxxxxxxxx"
}
}
jest.config.js:
module.exports = {
log: jest.fn(),
}
azure httptrigger function - index.js:
const iothubConnectionString = process.env["IOTHUB_CONNECTION_STRING"];
console.log( iothubConnectionString ) //undefined
My tests fail due to these configuration variables. I need to pass the test. anyone can you please help me.
local.settings.json is specific to Azure Functions Core Tools. As long as you use Core Tools CLI to run the function you can access environment variables defined in this file via process.env
I am trying to setup a timerTrigger azure function
My function.json:
{
"disabled": false,
"bindings": [
{
"type": "timerTrigger",
"direction": "in",
"name": "sampleCronTrigger",
"schedule": "*/5 * * * * *",
}
],
"entryPoint": "sampleCron",
"scriptFile": "index.js"
}
In this I need to set an environment variable, but I am not able to do so. I tried looking for some documentation but couldn't find anything which doesn't require some setup on the Azure console?
I can I define environment variables? Or If here is any way I can pass an input to the function, that works too.
App settings in a function app contain global configuration options that affect all functions for that function app. When you run locally, these settings are accessed as local environment variables.
Local settings file
The file local.settings.json stores app settings, connection strings, and settings for Azure Functions Core Tools. Settings in the local.settings.json file are only used by Functions tools when running locally. By default, these settings are not migrated automatically when the project is published to Azure. Use the --publish-local-settings switch when you publish to make sure these settings are added to the function app in Azure.
In Functions, app settings, such as service connection strings, are exposed as environment variables during execution. You can access these settings using process.env, as shown here in the GetEnvironmentVariable function:
module.exports = function (context, myTimer) {
var timeStamp = new Date().toISOString();
context.log('Node.js timer trigger function ran!', timeStamp);
context.log(GetEnvironmentVariable("AzureWebJobsStorage"));
context.log(GetEnvironmentVariable("WEBSITE_SITE_NAME"));
context.done();
};
function GetEnvironmentVariable(name)
{
return name + ": " + process.env[name];
}
There are several ways that you can add, update, and delete function app settings:
From Azure portal.
By using the Azure CLI.
When running locally, app settings are read from the local.settings.json project file.
References:
https://learn.microsoft.com/en-us/azure/azure-functions/functions-app-settings
https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node#environment-variables
https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-node#environment-variables
Additionally for retrieving values from local.settings.json, another way is to create an IConfigurationRoot object using ExecutionContext executionContext.
ExecutionContext can be added to function definition:
[FunctionName("FunctionName")]
public static async Task Run(
[ServiceBusTrigger(...)]
SomeMessage msg,
ILogger log,
ExecutionContext executionContext)
{
}
After that, you can instantiate an IConfigurationRoot instance, which you instruct to optionally load local.appsettings.json.
var configurationRoot = new ConfigurationBuilder()
.SetBasePath(executionContext.FunctionAppDirectory)
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
With the configurationRoot object, you can retrieve configuration values:
var value = configurationRoot["SomeKey"];
Example local.settings.json:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "...",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"SomeKey": "Value",
},
"Host": {
"LocalHttpPort": "7071"
}
}
I am trying to setup an Azure Function to run locally on my development environment. I wish to connect to a MongoDb database instance.
In my local.settings.json file I have added:
"ConnectionStrings": {
"DB_CONNECT_STRING": "mongodb://localhost:27017/MyDatabase"
}
In my function I then have:
module.exports = function (context, myTimer) {
console.log(process.env.DB_CONNECT_STRING);
context.done();
};
process.env.DB_CONNECT_STRING is undefined.
I assume I need to add some kind of prefix to the environment variable, but I can't find this documented anywhere. How do I specify a connection string and reference it in the function code?
Matt Mason is right.
In Node.js, we should specify app settings in the Values collection. These settings can then be read as environment variables by using process.env.
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"DB_CONNECT_STRING": "mongodb://localhost:27017/MyDatabase"
}
}
Then use process.env.DB_CONNECT_STRING to get the value.
For the purists out there, I found it. I set a breakpoint and evaluated "process.env" and found my connection string in this format:
ConnectionStrings:<ConnectionName>
So if my local.settings.json looks like this:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"FUNCTIONS_WORKER_RUNTIME": "node",
},
"Host": {
"CORS": "http://localhost:8080"
},
"ConnectionStrings": {
"Prod": "MyConnString"
}
}
Then I would access it like this:
const sqlConnString = process.env['ConnectionStrings:Prod'];
You have to use bracket notation because of the colon.