Ankit Kumar
Ankit Kumar

Reputation: 514

How to read a config json file inside a Azure Function app

I have a json Config file which I would like to read from inside the Azure function. We have by default localsettings.json file but I need a one more Json config file to read in my function code. Whats the best way, till now for my other projects I was able to read by below code but this wont work from inside Azure function.

 var builder = new ConfigurationBuilder()
        .SetBasePath(Path.Combine(Root))
        .AddJsonFile("DataFileConfiguration.json", optional: false);
         var config = builder.Build();
         var tableStorageOutput = new TableStorageConfiguration();
         config.GetSection("TableStorageRule").Bind(tableStorageOutput);

Upvotes: 2

Views: 7305

Answers (2)

Rod Ramírez
Rod Ramírez

Reputation: 1368

Oh boy this is long, I put a TL;DR:POC at bottom

This took me a while to figure out when I was working on it, so I decided to create a small guide about this.

  1. Create the metadata file: We call it appsettings.json just because we all worked in C# web APIs before and we were used to, but you can call it whatever you want. Make sure that this file is always copied when building the solution. Right click on the file over Solution Explorer => Properties => Copy to Output Directory => Copy always

  2. Create a class to strongly-type your appsettings json file

    public class AppSettings
    {
        public string SomeValue { get; set; }
    }
  1. Create a Startup.cs file in your .csproj that inherits from FunctionsStartup
    [assembly: FunctionsStartup(typeof(FunctionApp.Startup))]
    
    namespace FunctionApp
    {

        public class Startup: FunctionsStartup
        {
            private IConfigurationRoot Config = null;

            private IConfigurationRoot FunctionConfig(string appDir) =>
                Config ??= new ConfigurationBuilder()
                    .AddJsonFile(Path.Combine(appDir, metaDataFileName), optional: false, reloadOnChange: true)
                .Build();
        }
    }

Thanks to Anthony Brenelière for that. Reference

Implement the Configure method. This is where you will bootstrap all your DI services, for example:

    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddTransient<IService, SomeService>();
        //some other services
    }  

Inside your Configure method define your IOptions as:

builder.Services.AddOptions<AppSettings>()
                .Configure<IOptions<ExecutionContextOptions>>((settings, exeContext) =>
                FunctionConfig(exeContext.Value.AppDirectory).Bind(settings));

Now you can finally access to your data as:

    public class AzureFunction
    {
        private readonly AppSettings AppSettings;
        public AzureFunction(IOptions<AppSettings> appsettings)
        {
            AppSettings = appsettings.Value;
        }

        [FunctionName("AzureFunction")]
        public async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
            ILogger log)
        {
            var result = AppSettings.SomeValue;
            return new OkObjectResult(result);
        }
    }

Bonus track: As far as I know, there is no elegant way to inject an appsettings.json file in the constructor of the startup class as in web APIs.

    //we cannot do this in azure function (yet)
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

So, how can I access, for example to the SQL ConnectionString? I need it when stepping into Configure method so I can register the service somewhat like this:

            builder.Services.AddDbContext<SqlDbContext>(
                options => options.UseSqlServer(//howww???, I don't want to hard code it));

Well, the only way that I personally could make it work is:

For local development: Defining it in the local.settings.json as

  "ConnectionStrings": {
    "SqlConnectionString": "some connectionstring"
  }

And in the Startup class access it through Environment.GetEnvironmentVariable

    Environment.GetEnvironmentVariable("ConnectionStrings:SqlConnectionString")    

For Azure Web Apps:, If you are you are deploying to an App Service, the connection string should be defined on azure portal => your azure function => settings\configurationwith the same key as the json file to be able to work on both environments (local/cloud) at the same time.

enter image description here

But wait, there is more:

Azure App services require you to define the connectionstring in azure portal as per the image above, no biggie right? It makes some sense that they command how to set things up. After all, they will only set an environment variable in the app service with the key provided, in my example SqlConnectionString.

No, they configure your connectionstring with the key SQLCONNSTR_{name}. You can check this, if you go to the kudu console in azure over advance tools and do a >cmd set to list all the environment variables of your app service.

Big shout out to @johnwc for that pointer

TL;DR: I created a small POC to achieve this here: link

Upvotes: 1

Paul Lorica
Paul Lorica

Reputation: 763

Right click your 'DataFileConfiguration.json' file in the solution explorer -> Properties -> Copy to output folder = 'Copy always'

enter image description here

Upvotes: 2

Related Questions