[Configuration in Azure Functions Series - Part 3] Add ASP.NET Core configuration into an Azure Function project
Tags: azurefunctions, csharp, netcore
Published: 2019-12-09 10:26:58

---
title: [Configuration in Azure Functions Series - Part 3] Add ASP.NET Core configuration into an Azure Function project
published: true
description: This is part three of a series exploring .NET Core configuration, with an emphasis on Azure Functions.   In this article, we look at how we can add ASP.NET Core configuration into an Azure Function project and use IOptions<> to inject strongly-typed configuration objects into our functions.
series: Configuration in Azure Functions Series
tags: azure_functions, csharp, .net_core
  
cover_image: https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/bilbo-with-ring.jpg
canonical_url: https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part3-aspnet-in-functions/
---

This article was originally published at [blogs.siliconorchid.com](https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part3-aspnet-in-functions/) on 1-Nov-2019


**This is part three of a series exploring *.NET Core* configuration, with an emphasis on *Azure Functions*.   In this article,  we look at how we can add *ASP.NET Core* configuration into an *Azure Function* project and use `IOptions<>` to inject strongly-typed configuration objects into our functions.**

> In [part 1 of this series](https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part1-intro-and-aspnetcore-configuration/), we introduce the subject of configuration and review how *ASP.NET Core* configuration works.

> In [part 2 of this series](https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part2-azure-functions-configuration/), we look at how configuration in *Azure Functions (v2)* works and talk about some of the issues.

> In [part 3 of this series](https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part3-aspnet-in-functions/), we show how you could include *ASP.NET Core* configuration into an *Azure Function* project.

> In [part 4 of this series](https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part4-keyvault/), we look at using other configuration services, specifically *Azure App Configuration* and *Azure Key Vault*

<br/>
<br/>
<hr/>


## Should you even attempt to use *ASP.NET Core* configuration, using IOptions<>, in an *Azure Function*?  

This may seem like a very odd question to bring up straight away, especially when this article seems to be presenting a working solution.   

However, as a caveat before you rush to try this code out in your own solution, **you really need to go into this with your eyes open**, as the situation can get muddy very quickly.    

If you go ahead and use the code in this article, you'll end up with two somewhat disjointed configuration systems working in parallel.  This isn't ideal and will quite likely lead to confusion amongst your development team and conflict within your code.   

However, an option that uses file-based configuration may be a solution that works well for some of you, particularly if you are working with a large number of separate configuration items, deployed in a number of different places.  

> As a reminder from part 1, this series has been written from the perspective of the developer who may already be accustomed to developing with  *ASP.NET Core*, and is wanting to learn about the slightly different way that *Azure Functions v2* goes about handling application configuration. This is why we draw parallels to *ASP.NET Core* throughout this article on *Azure Functions*.

* **ASP.NET Core Configuration**. In [part 1]((https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part1-intro-and-aspnetcore-configuration/)) of this series, we covered how *ASP.NET Core* provides a relatively flexible system of configuration. Specifically good reasons include:  


    * a baseline file-based configuration, in the form of the file `appsettings.json`, that deploys to all environments.   
    * an abstraction of key-value pairs, that allow us to easily define structured configuration settings using json.
    * support for binding of configuration to strongly-typed objects, using the *Options Pattern*.
    * support for easy inclusion of those objects into our own code, using dependency injection of `IOptions<>`.


<br/>

* **Azure Functions Configuration**. In [part 2](https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part2-azure-functions-configuration/) of this series, we covered how *Azure Functions* were created to address several different requirements; they needed to be simple to use, cross-language and self-contained.   They were not intended to require the additional complication of having to setup and configure the host (as we do with *ASP.NET Core*).  We also talked about the fact that the runtime of *Azure Functions* has baked-in behaviour which means that  some aspects of configuration need to be provided in a fairly prescribed way:  

    * each *Function* method is defined by an Attribute (that defines its type) that is **hardcoded to accept certain parameters** which are used by the runtime/bindings.    These typically comprise of a **setting name rather than the setting value**.  
    * other configuration-settings, that are used within the body of the *Function* code itself, can be requested as needed, typically using `Environment.GetEnvironmentVariable("SomeConfigurationSetting")`
    * specific to the use of `local.setting.json`; configuration settings are expected to be located in the `Values` node as flat key-value pairs.  We cannot introduce nested JSON structures within the `Values` node, nor can we use certain characters to define hierarchy.  We can use a single-underscore to provide improved legibility.
    * out of the box, because there is no file-based baseline, all configuration needs to be defined repeatedly in different environments.  i.e. all of the configuration-settings need to be listed in the `local.settings.json` - and then repeated again in the Azure AppService configuration.  In a more complex distributed system,with duplicate instances of an AppService in multiple different [Azure Regions](https://azure.microsoft.com/en-gb/global-infrastructure/regions/), those configuration-settings need to be duplication for each instance.  

> Alternatively, if we wanted to share a common source of configuration, a solution that is readily supported, is to use *Azure App Configuration* (we'll cover this in part 4).

<br/>
<br/>
<hr/>

### Does this even work?

*ASP.NET Core* and *Azure Functions* have approaches to configuration that are compatible - but they don't really coexist together:  

* We can't supply configuration to the *Azure Functions* runtime without using the provided method Attributes.  As just mentioned, those *Function* Attributes (usually) dictate that we supply [string literal](https://jonskeet.uk/csharp/strings.html#literals) arguments for setting-names, not setting-values.   There is no opportunity to take advantage of strongly-typed `IOptions<>` here.
 
* The baked-in behaviour means that **the runtime will only be looking for configuration in the places that it supports**, such as `local.settings.json`.     The *Azure Functions* runtime **cannot see configuration from file sources that we define ourselves** in the host startup.  

<br/>

To illustrate how this becomes a problem, let's return to the sample code for `CosmosDBTrigger`, that we looked at earlier in part2 of the series.   We're going to try to combine it with an unexpected configuration source.  In this code sample, if we replace the `CosmosDBTrigger` **attribute parameter** at line 7 with `ConnectionStringSetting = "cosmosConnectionString"`

For reader convenience, here's that code again with the change highlighted:

<pre data-line="7"><code class="language-csharp">public static class Function1
{
    [FunctionName("Function2")]
    public static void Run([CosmosDBTrigger(
        databaseName: "databaseName",
        collectionName: "collectionName",
        ConnectionStringSetting = "cosmosConnectionString",
        LeaseCollectionName = "leases")]
           IReadOnlyList<Document> input, ILogger log)
    {
        if (input != null && input.Count > 0)
        {
            log.LogInformation("Documents modified " + input.Count);
            log.LogInformation("First document Id " + input[0].Id);
        }
    }
}
</code></pre>
  
It would now be fair to assume that next, we should add a corresponding setting into the root node of our [*ASP.NET Core* style]  `appsetting.json` file, like this:-

<pre data-line="2"><code class="language-csharp">{
  "cosmosConnectionString": "&lt;an-actual-connectionstring&gt;",
  "anotherUnrelatedConfigurationSetting" : "anotherValue"
}
</code></pre>

For the sake of this example, let's assume that this `appsetting.json` file has been correctly configured in the host startup, using the steps that we'll describe a little later in this article.   We should also assume that we haven't confused matters by defining a duplicate of the setting, in a location that is expected, such as `local.settings.json`.  The purpose of this test is to attempt to use, solely, the `appsettings.json` file.

If we now go ahead and try and run this, the *Azure Functions* will [throw a wobbly](https://www.urbandictionary.com/define.php?term=throw%20a%20wobbly), as the runtime does not know about this configuration source, even though we defined it in the host startup.

![screenshot showing unresolved configuration error](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/func-cannot-resolve.png#shadow)

<br/>
<br/>
<hr/>

It's easy to sound flippant when referring to "the baked-in behaviour" of the *Azure Functions* runtime, but we should be really mindful not to trivialise what *Azure Functions*, as a wider platform, is actually doing behind the scenes.

According to [this GitHub issue](https://github.com/Azure/azure-functions-host/issues/4464), which discusses a scenario that is very similar to the one presented in this article,  [Microsoft Developer Fabio Cavalcante ](https://github.com/fabiocav) offered this advice which is totally worth quoting here, as it provides further insight into how the platform works:-

> "...some infrastructure pieces, particularly in the consumption model, need to monitor trigger sources and some configuration options that control the Function App behavior. One example of such component is the scale controller.
In order to activate and scale your application, the scale controller monitors the event source to understand when work is available and when demand increases or decreases. Using Service Bus as an example; the scale controller will monitor topics or queues used by Service Bus triggers, inspecting the queue/topic lengths and reacting based on that information. To accomplish this task, that component (which runs as part of the App Service infrastructure) needs the connection string for each Service Bus trigger setup and, **today, it knows how to get that information from the sources we support. Any configuration coming from other providers/sources is not visible to the infrastructure outside of the runtime.**"
 


<br/>
<br/>
<hr/>

### How could this approach using supplemental configuration sources be useful to me?

As an example of where additional settings could be useful, let's refer back to the code sample for a `CosmosDbTriggered` Function, back in part 2.    In that example, provided by the MS templates, we can see that there are baked-in settings for wiring everything up to the CosmosDb listener.

It's likely that we'll want our function to perform a task such as adding a message to a completely separate [ServiceBus Queue](https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-dotnet-get-started-with-queues) service.     To make this work, we would need to supply configuration information relevant to that service.   Traditionally at this point, we would be adding multiple separate lines of code into our *Function* that uses things such as `Environment.GetEnvironmentVariable("ServiceBusUrl");` etc.

By instead supplying our *Function* code with a strongly-typed `IOptions<>` class, we can benefit from the aforementioned advantages associated with using *ASP.NET Core* style configuration.

<br/>
<br/>
<hr/>

### Do I have to use a separate AppSettings.json file?

We can choose any filename we like, it doesn't specifically need to be `appsettings.json`.  If we wanted to, we could even identify `local.setting.json` as the configuration source and shoehorn-in extra JSON nodes  - I really wouldn't recommend doing this though!  The key to making this work is to correctly identify the file in the `startup` class, using ` .AddJsonFile("appsettings.json", false)`,  which is then read by the host.

However, be mindful that a key reason for adopting this approach is so that we have the option to use `appsettings.json` as a baseline configuration that can be deployed to different environments.
    

<br/>
<br/>
<hr/>


## Dependency Injection in Azure Functions

You can read the official documentation here: [Use dependency injection in .NET Azure Functions
](https://docs.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection)

The [*Azure Functions* team](https://twitter.com/azurefunctions?lang=en) are always working super-hard on improving the platform.  It was announced at Build 2019 that *Azure Functions* had been updated to support native dependency injection (DI).  

In one fell swoop, many of the things possible in *ASP.NET Core* became available for use in *Azure Functions* also.

Originally, *Azure Function* classes were required to be static classes.  One of the notable recent changes made to support DI, is that ***Azure Functions*** **can now be created as instance methods**.  

This then means that, combined with the new native dependency injection framework, **we can inject objects into the constructor** of our *Function* class instances.  

Of specific interest to us, is the ability to inject `IOption<>` objects into out *Function* classes and work with them, just like we do with *ASP.NET Core* 

<br/>
<br/>
<hr/>


![image showing bilbo baggins with a scary face ring from lord of the rings](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/bilbo-scary-face.jpg#shadow)


## Let's do it!

<br/>


### 1) Explicitly tell the compiler which version of *.NET Core* SDK to use

This demo was created using *.NET Core v2* - specifically SDK 2.2.402
/ Runtime 2.2.7, which was the last version released, prior to being superseded by the newer *.NET Core v3*.

When testing this demo, I had recently installed the *.NET Core v3* SDK - which had just been made GA (at the time of writing).   The default behaviour for the compiler is to use the most recent version of the SDK installed.  

**Using the *.NET Core 3* SDK, I experienced an incompatibility/bug which caused the demo to fail during the build**. 

Very briefly, it was "blowing up" with the error : `Could not load file or assembly 'Microsoft.AspNetCore.Mvc.Abstractions...`.  I ran out of time attempting to fix this - but this may be a problem which is already resolved, by the time you read this article.  

In the meanwhile, to work-around the problem, we need to install and target a specific version of the SDK.   

To achieve this:

* download and install the last release of the [v2.2.x SDK from Microsoft](https://dotnet.microsoft.com/download/dotnet-core/2.2).    
* after installing, you can verify which SDK's you have installed by using the command `dotnet --info`
* add a new file `global.json` into the solution-level folder of the demo  (i.e. one above the project folder) and edit it with the following:-

<pre data-line="3"><code class="language-js">{
  "sdk": {
    "version": "2.2.402"
  }
}
</code></pre>

<br/>
<br/>
<hr/>

### 2) Set Framework Version and Add Nuget Packages in the project

* Update the `TargetFramework` to `netcoreapp2.2` (edit the `.csproj`)

We use this complete list of packages - versions used as indicated:   

* `Microsoft.NET.Sdk.Functions`  (v1.0.29)
* `Microsoft.Azure.Functions.Extensions`   (v1.0.0)
* `Microsoft.AspNetCore.App`  (v2.2.6)

> Do not confuse `Microsoft.AspNetCore.App` with `Microsoft.NetCore.App`

<br/>
<br/>
<hr/>

### 3) Update `local.settings.json` with a setting

The goal here is not really to use `local.setting.json`, but it will help to demonstrate that the configuration systems can work side-by-side in certain cases.

<pre data-line="6"><code class="language-js">{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet"
        "LocalSettingValue" : "Setting From local.settings.json"
    }
}
</code></pre>

<br/>
<br/>
<hr/>

### 4) Create `appSettings.json` and populate

This will depend on your own project, but this is an example of what the configuration could look like:

```javascript
{
    "ConfigurationItems": {
        "CommonValue": "Setting From appsettings.json",
        "SecretValue": "Do not save secret values in appsettings"
    }
}
```

You need to ensure that `appsetting.json` will be included as a deployable artefact of the build:
  
* If you are using Visual Studio, from *Solution Explorer*, right-click and select *Properties*.  Under "Copy to Output Directory", select "Copy always".

* Alternatively, for developers using other code editors, you can edit the `.csproj` like this:-

```xml
<ItemGroup>
    <None Update="appsettings.json">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
</ItemGroup>
```

<br/>
<br/>
<hr/>

### 5) Create user secrets


* From the *Solution Explorer*, go ahead and right-click on the project file, 
* Select "Manage User Secrets".    A new `secrets.json` file will open - populate it with the following code:


```javascript
{
    "ConfigurationItems": {
        "SecretValue": "Secret Setting From User Secrets"
    }
}
```

As a reminder from part 1 of this series, behind the scenes, the "Manage User Secrets" option will:

* create a new key within the `.csproj` file, with the name `UserSecretsId` and a new GUID value.
* create a new folder in your OS user-profile which mirrors the GUID.  Within this folder, is where you can find the actual `secrets.json` file - although Visual Studio makes it easy to open this.

<br/>
<br/>
<hr/>

### 6) Create a Model which will bind to configuration

We're going to take our string-based configuration file and bind the values to a strongly-typed object.   We should make a model class for this purpose:

```csharp
    public class ConfigurationItems
    {
        public string CommonValue { get; set; }
        public string SecretValue { get; set; }
    }
```

<br/>
<hr/>

### 7) Create a startup class

A project created from an *Azure Functions* template is minimal and doesn't include a `Startup.cs` class, so let's add that in next.

```csharp
using System;
using System.Reflection;

using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

using FunctionApp1;
using FunctionApp1.Models;

[assembly: FunctionsStartup(typeof(Startup))]
namespace FunctionApp1
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            var config = new ConfigurationBuilder()
                   //.SetBasePath(Environment.CurrentDirectory)  ← do not use
                   .SetBasePath(Directory.GetCurrentDirectory())
                   .AddJsonFile("appsettings.json", false)
                   .AddUserSecrets(Assembly.GetExecutingAssembly(), false)
                   .AddEnvironmentVariables()
                   .Build();         

            builder.Services.Configure<ConfigurationItems>(config.GetSection("ConfigurationItems"));

            builder.Services.AddOptions();
        }
    }
}
```

Take care not to use `.SetBasePath(Environment.CurrentDirectory)`.  This is provided in most examples you'll find on the web.   This works fine for development, but **does not work when you publish to Azure**.  Instead, you should use this: `.SetBasePath(Directory.GetCurrentDirectory())`

Also take care not to omit the `[assembly: ...]` attribute, found adjacent to the `namespace` section in the example above, otherwise your startup class will not actually be invoked at startup.  The project will still build without it though, which could lead to confusion.

<br/>

> If you've been looking at other guides related to this subject on the web,, you may have found code examples which use `WebJobsStartup` instead of `FunctionsStartup` and `IWebJobsBuilder` instead of `IFunctionsHostBuilder` … these are constructs that come with *ASP.NET Core*.  As far as I can tell,  the *Azure Functions* team has added a `Functions` variant in mid-April 2019, which looks to be a wrapper of `IWebJobsStartup` etc - check out the [source code for azure-functions-dotnet-extensions](https://github.com/Azure/azure-functions-dotnet-extensions/tree/master/src/Extensions/DependencyInjection).

<br/>
<br/>
<hr/>

### 8) In your Azure Function class

Finally, in our *Function* class, we can now inject your strongly-typed configuration options, like this:

```csharp
using System;
using System.Threading.Tasks;

using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;

using FunctionApp1.Models;

namespace FunctionApp1
{
    public  class Function1
    {
        private readonly ConfigurationItems _configurationItems;

        public Function1(IOptions<ConfigurationItems> configurationItems)
        {
            _configurationItems = configurationItems.Value;
        }


        [FunctionName("Function1")]
        public  async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req
            )
        {
            string localSettings = Environment.GetEnvironmentVariable("LocalSettingValue"); // Included so as to demo regular approach
            string commonValue = _configurationItems.CommonValue;
            string secretValue = _configurationItems.SecretValue;

            return new OkObjectResult($"Local Value : '{localSettings}' | Common Value : '{commonValue}' | Secret Value : '{secretValue}'");
        }
    }
}
```

> When working with an `IOptions<T>` type, don't forget to include `.Value` to get to the actual configuration settings.

<br/>
<br/>
<hr/>

### 9) Run the program

We should see output like this:-

```
Local Value : 'Setting From local.settings.json' | Common Value : 'Setting From appsettings.json' | Secret Value : 'Secret Setting From User Secrets'
```


<br/>
<br/>
<hr/>

In the final part of this series, we look at using other configuration services, specifically *Azure App Configuration* and *Azure Key Vault*.


<a href="https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part4-keyvault/" class="button is-primary">
 <i class="fas fa-file-alt ml-1" style="margin-right:10px;" > </i> NEXT:  Read Part 4</a>