Nosmadas
Nosmadas

Reputation: 682

Azure Functions - using appsettings.json

Is it possible to use an appsettings.json file in Azure Functions?

There is documentation for environment variables here..

https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-csharp#environment-variables

..however we use Octopus for deployments and would really like to have appsettings version controlled.

We have tried using

{
  "frameworks": {
    "net46": {
      "dependencies": {
        "Microsoft.Extensions.Configuration": "1.0.0",
        "Microsoft.Extensions.Configuration.Json": "1.0.0"
      }
    }
  }
}

but constantly get

2016-11-23T15:27:03.811 (12,16): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Runtime, Version=4.0.0.0

Even being able to supply/update environment variables via Octopus would be sufficient for our needs.

Please advise.

Upvotes: 33

Views: 57844

Answers (10)

Nick Pirocanac
Nick Pirocanac

Reputation: 161

For anyone that comes across this in 2025, here's how I did it for a v4 Azure Function using isolated worker model. Because the default configuration loader relies on the environment, I did not reload the environment with Configuration builder, but it's up to you on how you want the configuration settings be applied. In the below example, I am preferring the setting in this order:

  • Environment
  • appsettings.json
  • appsettings.{ASPNETCORE_ENVIRONMENT}.json

Don't forget to mark your appsettings.json as "copy if newer" in the properties for each *.json file so that they will get copied into your bin directory. I also like to make appsetting.json non-optional so that if it is missing the application fails immediately. This can help find any deployment errors.

Program.cs

using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;

var builder = FunctionsApplication.CreateBuilder(args);

builder
    .ConfigureFunctionsWebApplication();

builder.Services
    .AddApplicationInsightsTelemetryWorkerService()
    .ConfigureFunctionsApplicationInsights();

var configuration = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
    .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true)
    .Build();

builder.Configuration
    .AddConfiguration(configuration);

builder.Build().Run();

Upvotes: 0

Fabio Maulo
Fabio Maulo

Reputation: 466

Yes you can add an appsettings.json file to your function app.

var host = new HostBuilder()
        .ConfigureAppConfiguration((context, confBuilder) => {
            confBuilder.AddJsonFile("appsettings.json", optional: false);
            if (context.HostingEnvironment.IsEnvironment("local"))
            {
                confBuilder.AddJsonFile("appsettings.local.json", optional: true);
            }
        })
        .ConfigureFunctionsWorkerDefaults()
        .ConfigureServices((hostContext, services) => 
        {
            services
            .AddApplicationInsightsTelemetryWorkerService()
            .ConfigureFunctionsApplicationInsights();

            services.ConfigureApp(hostContext.Configuration);
        })
        .Build();

host.Run();

The HostBuilder is just the same you can use in any of yours exe so you can add any configuration file to it. In the example the ConfigureApp method is just an extension method:

public static class RegisterServices
{
    public static IServiceCollection ConfigureApp(this IServiceCollection store, IConfiguration configuration)
    {
        store.AddSingleton(configuration.GetSection("MyCompany:MyApp:Pizza").Get<PizzaOptions>());
        return store;
    }
}

Do not forget to add your appsettings.json to you prj

  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
    <None Update="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>

keep coding

Upvotes: 1

Yoro
Yoro

Reputation: 1730

Maybe this simple solution would be useful:

[assembly: FunctionsStartup(typeof(AzureFunctions.Startup))]

namespace AzureFunctions;

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        var context = builder.GetContext();
        var config = context.Configuration; //Here you go!
    }

    public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
    {
        var 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); //For example enviroment name can be: Development
    }

}

Upvotes: 3

Nilesh Sawant
Nilesh Sawant

Reputation: 1682

Configuration source customization is available beginning in Azure Functions host versions 2.0.14192.0 and 3.0.14191.0.

To specify additional configuration sources, override the ConfigureAppConfiguration method in your function app's StartUp class.

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();
        }
    }
}

// update configuration in csproject

<None Update="appsettings.json">
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>      
</None>

<None Update="appsettings">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    <CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>

Instead of everytime using configuration, you can inject option class whenever required as below. From inside the Startup.Configure method, you can extract values from the IConfiguration instance into your custom type using the following code:

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

Function class:

using System;
using Microsoft.Extensions.Options;

public class HttpTrigger
{
    private readonly MyOptions _settings;

    public HttpTrigger(IOptions<MyOptions> options)
    {
        _settings = options.Value;
    }
}

Refer: https://learn.microsoft.com/azure/azure-functions/functions-dotnet-dependency-injection#customizing-configuration-sources

Upvotes: 11

Nitin Sapru
Nitin Sapru

Reputation: 31

Tried and test approach where we can:

  1. Create an appsettings.json within your function app project.
  2. You would need add a Startup.cs class within your project inheriting from FunctionsStartup class. This would expose a method Configure(IFunctionsHostBuilder builder) for overriding.
  3. For control on level of customisation, I would say to extend IFunctionsHostBuilder class lets say it is (IFunctionsHostBuilderExtensions.cs) and add an extension method to add a new configuration builder to the same. This gives us the benefit of controlling how we want to configure the appsettings setup at runtime.
  4. Once, done, you can call the newly created extension method by either passing the entire file path for the appsettings or just the name.( You can configure base path for you appsettings in the extension method to avoid hastiness within the code).
  5. Once you build the extension method, you will get a service ready for injection i.e. IConfiguration, which can be used as anywhere within the codebase.
  6. You can also add multiple providers for the appsettings, like Azure Key Vault, AWS Secret Manager etc. For the same , all you need to do is add an extension method within the IFunctionsHostBuilderExtensions class & call them within your startup class.
  7. If you want to keep things more neat, you can implement a wrapper around the IConfiguration service to expose a single GetSettings(string key) method which would return the settings that you want from a central collection of providers within IConfiguration.

Some code snips below:

/// <summary>
///     Represents the startup class of the function app.
/// </summary>
public class Startup : FunctionsStartup
{
    private const string LocalSettingFileGenericName = "appsettings";
    private const string LocalSettingFileExtension = "json";

    /// <summary>
    ///     Configures the host builder for the function app.
    /// </summary>
    /// <param name="builder">The function app host builder.</param>
    public override void Configure(IFunctionsHostBuilder builder)
    {
        try
        {
            builder.AddConfiguration((configurationBuilder) =>
            {
                var configuration = typeof(Startup).Assembly.GetCustomAttribute<AssemblyConfigurationAttribute>().Configuration;

                var configurationFileName = !string.Equals(configuration, "Release")
                    ? $"{LocalSettingFileGenericName}.{configuration.ToLowerInvariant()}.{LocalSettingFileExtension}"
                    : $"{LocalSettingFileGenericName}.{LocalSettingFileExtension}";

                var configurationSource = configurationBuilder
                    .AddJsonFile(configurationFileName, false, true)
                    .AddEnvironmentVariables();

                var partialConfigurationBuilder = configurationSource.Build();

                var keyVaultName = partialConfigurationBuilder.GetSection(ConfigurationKeys.KeyvaultName)?.Value;

                return configurationSource
                       .AddKeyVaultWithManagedIdentity(keyVaultName)
                       .Build();
            });

IFunctionBuilderExtensions.cs

 internal static class IFunctionsHostBuilderConfigurationsExtensions
{
    private const string keyVaultGenericUri = "https://{0}.vault.azure.net/";

    /// <summary>
    ///     Provides an extension method to add configuration provider.
    /// </summary>
    /// <param name="builder">The function app host builder.</param>
    /// <param name="configBuilderFunc">The delegate to pointing to configuration builder.</param>
    /// <returns>The function app host builder</returns>
    public static IFunctionsHostBuilder AddConfiguration(
        this IFunctionsHostBuilder builder,
        Func<IConfigurationBuilder, IConfiguration> configBuilderFunc)
    {
        var configurationBuilder = builder.GetBaseConfigurationBuilder();

        var configuration = configBuilderFunc(configurationBuilder);

        builder.Services.Replace(ServiceDescriptor.Singleton(typeof(IConfiguration), configuration));

        return builder;
    }

    /// <summary>
    ///     Provides an extension method to add Azure Key Vault as a configuration provider.
    /// </summary>
    /// <param name="builder">The configuration builder.</param>
    /// <param name="keyvaultName">The azure key vault name.</param>
    /// <param name="authenticationClientId">The AAD application clientId.</param>
    /// <param name="authenticationClientSecret">The AAD application clientSecret.</param>
    /// <returns>The configuration builder.</returns>
    public static IConfigurationBuilder AddKeyVaultWithManagedIdentity(
        this IConfigurationBuilder builder,
        string keyvaultName)
    {
        if (string.IsNullOrWhiteSpace(keyvaultName))
        {
            return builder;
        }

        var serviceTokenProvider = new AzureServiceTokenProvider();
        var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(serviceTokenProvider.KeyVaultTokenCallback));

        var keyVaultUri = string.Format(keyVaultGenericUri, keyvaultName);

        builder.AddAzureKeyVault(
            keyVaultUri,
            keyVaultClient,
            new DefaultKeyVaultSecretManager());

        return builder;
    }

    private static IConfigurationBuilder GetBaseConfigurationBuilder(this IFunctionsHostBuilder builder)
    {
        var configurationBuilder = new ConfigurationBuilder();

        var descriptor = builder.Services.FirstOrDefault(
            service => service.ServiceType == typeof(IConfiguration));

        if (descriptor?.ImplementationInstance is IConfiguration configRoot)
        {
            configurationBuilder.AddConfiguration(configRoot);
        }

        var rootConfigurationBuilder = configurationBuilder.SetBasePath(GetCurrentDirectory());

        return rootConfigurationBuilder;
    }

    private static string GetCurrentDirectory()
    {
        var currentDirectory = Path.GetDirectoryName(
            Assembly.GetExecutingAssembly().Location);

        return currentDirectory.Replace("bin", "{Your settings directory}");
    }

Example for wrapper implementation:

  /// <summary>
///     Represents the configuration settings provider class.
/// </summary>
public class ConfigurationSettings : IConfigurationSettings
{
    private readonly IConfiguration configurationSource;

    /// <summary>
    ///     Initializes the class of type <see cref="ConfigurationSettings"/>.
    /// </summary>
    /// <param name="configurationSource">The configuration source.</param>
    public ConfigurationSettings(
        IConfiguration configurationSource)
    {
        this.configurationSource = configurationSource;
    }

    ///<inheritdoc/>
    public T GetSetting<T>(string key)
    {
        try
        {
            if (!configurationSource.GetSection(key).Exists())
            {
                throw new ConfigurationDoesNotExistException(
                    $"The configuration with key {key} does not exist in appsetting or key vault.");
            }

            return (T)Convert.ChangeType(configurationSource.GetSection(key)?.Value, typeof(T));
        }
        catch (InvalidCastException)
        {
            throw;
        }
        catch (Exception)
        {
            throw;
        }
    }
}

Upvotes: 2

In Azure Functions, setting are stored in local.settings.json (create this file if doesn't exist in your solution/ name should be exact as mentioned).

once you add setting file, you have to configure it under your Run() method as mentioned bellow,

enter image description here

When Accessing setting, use below

IConfigurationRoot config;
config["fromEmail"];

use below command to publish settings

func azure functionapp publish *YourAppName* --publish-local-settings -i

enter image description here

Upvotes: 3

armadillo.mx
armadillo.mx

Reputation: 1001

According to the changes made to the configuration files, you should only use local.settings.json since the appsettings.json was renamed to local.settings.json

Reference to the change: azure-functions-cli

Upvotes: 15

Jose Roberto Araujo
Jose Roberto Araujo

Reputation: 339

For your needs the answer is YES! Azure Functions can use appsettings.json for your configurations. But there are some ordering sequence that Azure will do when a Function is requested.

1º) Azure will look for that KEYS that you used on .GetEnvironmentVariables("[KEY]") method, through Keys that were configured on Application Settings blade in Azure Functions settings

2º) If Azure wasn't able to find out that configurations through Application Settings keys, then Azure will try looking for after appsettings.json file into your root folder of the Function that you working on.

3º) Finally, if Azure wasn't able to find out this keys either on Application Settings neither on appsettings.json file, then Azure will do the last attempt to find out web.config for looking for into this file appsettings section keys.

For your appreciation, you'll able to find out these configurations by the sample on my github repo: here and here

I hope that these information help you.

Upvotes: 27

Aureliano Buendia
Aureliano Buendia

Reputation: 5

For dependencies you should use/create the project.json inside your function. There you can specify your dependencies. Please check: https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-csharp#package-management

For example:

{
  "frameworks": {
    "net46":{
      "dependencies": {
        "Microsoft.ProjectOxford.Face": "1.1.0"
      }
    }
   }
}

Upvotes: -3

mathewc
mathewc

Reputation: 13558

Only environment variables are supported for app settings and connection strings. appsettings.json is not supported.

However, you can use Azure Resource Manager (ARM) Templates to configure the settings for your Function App. Here's a blog post that describe this in more detail.

Upvotes: 9

Related Questions