[Configuration in Azure Functions Series - Part 1] Introduction to .NET Core configuration
Tags: azurefunctions, csharp, netcore
Published: 2019-12-09 10:24:54

---
title: [Configuration in Azure Functions Series - Part 1] Introduction to .NET Core configuration
published: true
description: This is part one of a series exploring .NET Core configuration, with an emphasis on Azure Functions.   In this article, we introduce the subject of configuration in general and look at how ASP.NET Core configuration is recommended to be used.
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/part1-intro-and-aspnetcore-configuration/
---

This article was originally published at [blogs.siliconorchid.com](https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part1-intro-and-aspnetcore-configuration/) on 1-Nov-2019


**This is part one of a series exploring .NET Core configuration, with an emphasis on Azure Functions.  In this article, we introduce the subject of configuration in general and look at how *ASP.NET Core* configuration is recommended to be used.** 

> 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/>
<hr/>

## Overview

Welcome to this series of four articles where we'll be covering the topic of application configuration, looking at both ***ASP.NET Core*** and ***Azure Functions v2***.   

The 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. 

We'll cover how and why things are different, possible sources of confusion and provide some working examples.   In the final part, we'll look at how to integrate powerful Azure services that can help to improve your application configuration. 


<br/>
<br/>

> Throughout this series, please be conscious that we will be referring to the following with **deliberate distinction**:   

> * [***.NET***](https://en.wikipedia.org/wiki/.NET_Framework) (AKA ".NET Framework") is a Windows-only software framework, dating back to 2002.

> * [***ASP.NET***](https://en.wikipedia.org/wiki/ASP.NET) is a  server-side web application framework, that expands upon the original  *.NET* framework.  

> * [***.NET Core***](https://en.wikipedia.org/wiki/.NET_Core) is a higher-performance, cross-platform and open-source software framework, introduced in 2016. 

> * [***ASP.NET Core***](https://en.wikipedia.org/wiki/ASP.NET_Core) is a server-side web application framework, that expands upon the newer *.NET Core* software framework. 

> * ***Azure Functions v1***  is Microsoft's initial offering of a "serverless" platform, [released in November 2016](https://azure.microsoft.com/en-gb/blog/announcing-general-availability-of-azure-functions/).  It supports a number of languages, including *.NET*, but not *.NET Core*. 

> * ***Azure Functions v2***  is the second iteration of the "serverless" platform, [released in September 2018](https://azure.microsoft.com/en-gb/blog/introducing-azure-functions-2-0/).  It shifted the underpinning software framework from *.NET* to *.NET Core*.  

> **Unless specified otherwise, assume that any mention of *Azure Functions* in this series, relates specifically to v2**


<br/>
<hr/>

## Introduction

### Configuration - Where have we come from?

If you've worked as a developer using Microsoft technologies for a number of years, it is most likely that you will have developed web applications using the *ASP.NET Framework*.   In which case, you will be familiar with the venerable `web.config` file.   

For the benefit of new developers, it may be useful to know that this configuration system dates all the way back to the release of the original *ASP.NET*, back in 2002.  For a very long time now, it has been the defacto, convention-based, way to manage configuration. 

Configuration in a `web.config` file mixes server settings and application settings together in a file that looks partly like this:-

```xml
<configuration>
 <appSettings>
  <add key="connectionString"
   value="Server=localhost;UID=sa;PWD=secret;Database=Northwind" />
 </appSettings>
</configuration>
```
To access configuration settings in our application code, we would add something like the following, directly in the place where it was needed:
```csharp
var connectionString = ConfigurationSettings.AppSettings( "connectionString" )
```

<br/>
<hr/>

### Configuration - Where are we now?

With the 2016 release of *.NET Core* and *ASP.NET Core*, the way application configuration was supported changed significantly and, as developers, the scope of what we needed to know about this subject broadened greatly.    

This is particularly true when it comes to the topic of *"where should different types of configuration information be stored - and where should it not be stored?"*.  

With the relatively recent [release of *Azure Functions v2*](https://azure.microsoft.com/en-gb/blog/introducing-azure-functions-2-0/) in September 2018, Microsoft shifted from using the *.NET Framework*, to instead use *.NET Core*.  

For the *ASP.NET Core* developer in particular, there is now a synergy that makes the adoption of *Azure Functions* a really appealing proposition.

However, when it comes to the subject of configuration, the shift from *ASP.NET Core* to *Azure Functions* isn't entirely frictionless.   It is this main theme, that we will attempt to address in this series.

<hr/>

Whilst researching these articles, two observations became apparent:

* Although Microsoft promotes a harmonised technology stack, there is a *slight* lack of cohesion/consistency between their products.  This is noticeable when you are familiar with some of the conventions found in *ASP.NET Core* and arrive at *Azure Functions* expecting things to work in *exactly* the same way.

* Because there are many options to tackle, what is essentially the same basic task, it's easy to feel overwhelmed with choice.   

These observations are truly not intended as a criticism of Microsoft, but it is indicative that their products are created, maintained and supported by a large number of people across several different teams.  Furthermore, each product requires many people to create and maintain comprehensive documentation, with a consistent and cohesive message that dovetails with other documents - this alone is not a trivial task!  

This series is the outcome of having collated various sources of documentation together.  Hopefully it will be a useful guide for developers shifting between, or integrating, the various technologies that we'll look at. 

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


![image gandalf entering hobbiton from the lord or rings movie](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/gandalf-entering-hobbiton.jpg#shadow)

## Modern .NET Core configuration, in general

If we distil the subject of configuration down to its most basic concept, the *.NET Core* libraries provide us with an API that offers a collection of key/value pairs.  

Configuration information is combined together from separate **layers**, from one or more different sources known as ***Configuration Providers***.    

Where we require an ***environment-specific*** piece of configuration (e.g. a feature switch setting), or ***secrets***  (e.g. a sensitive API key to another service), we can supplement or replace a configuration resource with information from additional other sources of configuration.  

*Configuration Providers* are (usually) registered in the initialisation code of our project and locate the required information under the direction of the application and the specific environment within which our program is running.

According to the [official documentation](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/index?view=aspnetcore-3.0), at the time of writing, the list of possible *configuration providers* include:

* [Azure Key Vault](https://azure.microsoft.com/en-gb/services/key-vault/)
* [Azure App Configuration](https://docs.microsoft.com/en-us/azure/azure-app-configuration/overview)
* [Command-line arguments](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.0#command-line-configuration-provider)
* [Custom providers (installed or created)](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.0#custom-configuration-provider)
* [Directory files](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.0#file-configuration-provider)
* [Environment variables](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.0#environment-variables-configuration-provider)
* [In-memory .NET objects](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.0#memory-configuration-provider)
* [Settings files](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.0#file-configuration-provider)

> Configuration providers (for example *Azure Key Vault*) are integrated to our project by adding the appropriate Nuget Package and registering that provider into the WebHost Builder in `startup.cs` class.   We'll explain exactly how to go about doing this, in part four of this series.

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


## Configuration, the ASP.NET Core way

You can read the official and in-depth documentation regarding *ASP.NET* configuration here: [Configuration in *ASP.NET Core*](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/index?view=aspnetcore-3.0).  

When we create a *.NET Core* WebApp (either MVC or WebAPI) - and assuming that we use the default templates - we'll find ourselves working with a file-based configuration-source called `appsettings.json`. 

Broadly speaking, `appsettings.json` should be considered as the baseline configuration resource for our web application.   

Configuration-settings in `appsettings.json` are read using the [File Configuration Provider](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.2#file-configuration-provider) - specifically the [JSON Configuration Provider](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.2#json-configuration-provider).

Use of this file-based source is not a baked-in behaviour of the *ASP.NET Core* runtime - it is facilitated by calling the method `CreateDefaultBuilder ` from within the application startup code `program.cs`.  This "default builder" loads configuration from the various sources in a certain order - refer to the section
[Default configuration](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/index?view=aspnetcore-3.0#default-configuration) for more info.   



`appsettings.json` is structured JSON, so this allows us to freely add groupings to our configuration information.  For example:

```
{
"EmailSettings": {
     "ApiKey": "secretKeyValue",
     "FromAddress": "do-not-reply@test.com"
     },
"FeatureSwitches": {
    "EnableFeatureOne": true,
    "EnableFeatureTwo": false,
     },
}
```

<br/>

We can expect `appsettings.json` to be deployed to all environments.  For example, when we build/publish (locally or to Azure), this file is literally copied as a deployment artefact.

![image of azure portal showing appsetting.json deployed as artefact](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/appsetting-copied-to-azure.png#shadow)

<br/>
<br/>

Because the configuration is **layered**, `appsettings.json` is used first and is then overlaid with replacement values from other configuration providers, such as the [*User Secrets*](https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-3.0&tabs=windows) provider.   

> N.B. To clarify: when we create those additional configuration resources, we **only need to specify the individual keys to be overwritten** - we don't need to create an entire copy of each and every item in the baseline configuration.  

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

### Which options are commonly used with ASP.NET Core?

We listed all of our choices just a moment ago, but let's look  a little more closely at some of the options that are commonly used:-


* **Environment-specific appsetting variants** (file-based sources) such as `appsettings.development.json` or `appsettings.production.json`, are an overlay of the baseline file-based configuration.  They are used selectively at runtime, depending on the name of the Environment that has been set. 

    As with the primary file, `appsetting.json`, these remain intended for non-secret settings and   are included in version control. 

    You can read about environments here at [Microsoft Documentation : Use multiple environments in ASP.NET Core.](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-3.0)

     *Environment-specific appsetting variants* should not be confused with the similar-sounding *Environment Variables*.  We do however need to define the "environment name" using the *Environment Variable* `ASPNETCORE_ENVIRONMENT`.  

    We can set any name that we like, but the *ASP.NET Core* framework only natively supports three variants:   `Development`, `Staging` and `Production`.   If no value is set, `Production` is used as default.  

    In development, you will typically find `ASPNETCORE_ENVIRONMENT` declared in the file `properties/launchsettings.json`

    When we talk about "native framework support", we're referring to the fact that we have built-in features that allow us to react selectively to the stated environment.  As examples of how this is consumed, consider this C# code in the `startup.cs` class and also an example of a Razor tag :-

```csharp
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
...
```

```razor
<environment include="Development"><p>Development mode</p></environment>
<environment include="Staging"><p>Staging mode</p></environment>
```

   To make use of these variants, we simply need to include `appsettings.development.json` or `appsettings.staging.json` files in our project.   We can include `appsettings.production.json` in our project if we want to purposefully separate production settings from a default baseline configuration.

>  Tip:  If you cannot see these files in Visual Studio, be aware that the *Solution Explorer* collapses the variants - click the caret next to the file to expand the view:

> ![image from visual studio showing nested appsettings](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/appsettings-variants-in-vs.png#shadow)


<br/>
<br/>


* [***User Secrets***](https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-3.0) **for local development secrets**.   The `secrets.json` file is stored outside of our project code, within our Operating System user profile.   This keeps it completely away from version control and provides [access control](https://en.wikipedia.org/wiki/Access_control) via our operating system.  

    If you aren't familiar with *User Secrets*, head over to [this beginner-friendly article](https://www.twilio.com/blog/2018/05/user-secrets-in-a-net-core-web-app.html) for an introduction and step-by-step instructions.

    <br/>

    If you create a new MVC/WebAPI project from the MS templates and right-click on the project file, you will find the option "Manage User Secrets".   

    If you repeat this exercise, by creating an empty *Azure Function* (or indeed, just a *Console App*), you will find the "Manage User Secrets" option doesn't display.

    The key to enabling this menu option is the presence of the package `Microsoft.Extensions.Configuration.UserSecrets`.   Adding either this package or the `Microsoft.NETCore.App` meta-package, to your project, will enable the option in the menu.

    ![image showing User Secrets menu option](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/user-secrets-dialogue.png#shadow)

    Behind the scenes, when you use this menu item, VS will have added a new `<UserSecretsId>` node and Guid value into your `.csproj`.  At the same time, a new folder that matches the Guid, will have been created inside your user profile. Inside this folder we can expect to find the file `secrets.json` which will partly mirror the structure of the `appsettings.json`.

    <pre data-line="5"><code class="language-xml">&lt;Project Sdk="Microsoft.NET.Sdk"&gt;
  &lt;PropertyGroup&gt;
    &lt;TargetFramework&gt;netcoreapp2.2&lt;/TargetFramework&gt;
    &lt;AzureFunctionsVersion&gt;v2&lt;/AzureFunctionsVersion&gt;
    &lt;UserSecretsId&gt;550b1379-cb4e-42ec-aa0c-72a5ac8f3700&lt;/UserSecretsId&gt;
  &lt;/PropertyGroup&gt;
</code></pre>

    ```
C:\Users\<your username>\AppData\Roaming\Microsoft\UserSecrets\<UserSecretsId>
```

    It is this separation of files, well away from the rest of your source code, that gives us a clear delineation between files that should be secret and those that should be in version control.


<br/>
<br/>


* [***Azure AppService Application settings***](https://docs.microsoft.com/en-us/azure/app-service/configure-common) **for [PaaS](https://azure.microsoft.com/en-gb/overview/what-is-paas/) cloud deployment.**    For a majority of scenarios, this is where all of our environment-specific configuration is defined when deployed to an Azure AppService.  

    If you aren't familiar with *Azure AppService Application settings*, check out [Microsoft Documentation: Configure an App Service app in the Azure portal](https://docs.microsoft.com/en-us/azure/app-service/configure-common).   

    Azure AppService support the concept of separate ["deployment slots"](https://docs.microsoft.com/en-us/azure/app-service/deploy-staging-slots), which offer us the option of multiple similar environments (e.g. production, UAT and a test versions) - each with slot-specific configuration if required.

    Take care not to confuse *"Azure AppService Application settings"* with the similarly-named *"Azure App Configuration"*, as this is another Azure service.  We'll look at this service in [part 4 of this series](https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part4-keyvault#azureappconfiguration).

    With regards to *secrets* specifically, we could safely add these configuration items into *Azure AppService Application settings*.  There is nothing inherently insecure about doing this (from an external-intrusion perspective) as values are encrypted at rest.  

    However, a potential concern is that anyone with legitimate permission to access the Azure AppService, will also be able to view these secrets.  This may be an issue depending on your organisation (a problem solved by using *Azure Key Vault*, which we'll look at in  [part 4 of this series](https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part4-keyvault#azurekeyvault)).

<br/>

> Tip: As an alternative to editing values directly into the Azure Portal, [this AzureTipsAndTricks article](https://microsoft.github.io/AzureTipsAndTricks/blog/tip130.html) shows us how to update Azure settings, in Visual Studio, when publishing.


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

![animated gif of gandalf telling frodo to keep ring secret](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/gandalf-keep-it-safe.gif#shadow)

### Keep it secret.  Keep it safe!

The `appsettings.json` file can be expected to be included in version control, so it must not include secrets (e.g. things such as a database connection string that includes a login credential). 


Although the actual *secret value* should itself not be included in version control, it is recommended that you still retain the *configuration-item key* in the `appsettings.json`. Instead of providing the actual secret value, we can add a message with some variant of  "do not include here").  

* By doing this, we can use `appsetting.json` as a working manifest of sorts, listing all expected configuration items for the project, along with the expected structure. Although we provide unusable key-values, we can trust that this will still work fine, as the actual working values will be substituted at runtime.  
* This provides a way to clearly communicate amongst your development team, which configuration items are **supposed** to be present.  It also could be said that regularly seeing this message serves to reinforce the need for the development team to think about where they store configuration items.

To illustrate this, an `appconfig.json` and `secrets.json` pair could look like this:-

Firstly, the `appconfig.json`:-

```
{
"Logging": {
    "IncludeScopes": false,
    "LogLevel": {
        "Default": "Debug",
        "System": "Information",
        "Microsoft": "Information"
    }
},
"ConnectionStrings": {
    "DefaultSql": "Do not specify here. Set in Azure AppConfiguration or User Secrets",
    "AzureStorage": "UseDevelopmentStorage=true"
},
"EmailSettingsConfig": {
    "ApiKey": "Do not specify here. Set in Azure AppConfiguration or User Secrets",
    "FromAddress": "do-not-reply@test.com"
}
```
<br/>
Combined with a `secrets.json`:-

```
{
"ConnectionStrings": {
    "DefaultSql": "Server=tcp:[serverName].database.windows.net;Database=myDataBase;
User ID=[secretDbLogin]@[serverName];Password=secretPassword;Trusted_Connection=False;
Encrypt=True"
},
"EmailSettingsConfig": {
    "ApiKey": "secretAccountKey"
}
```
<br/>
<br/>
<hr/>

![image of hobbit hole](https://blogs.siliconorchid.com/images/coding-inspiration/azure-function-configuration/hobbiton.jpg#shadow)

### Strongly-typed Configuration models

A really nice feature that *ASP.NET Core* introduced, alongside the use of `appsettings.json`, was support for the [Options Pattern](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-3.0). 

This lets us [bind nodes within configuration files to strongly-typed C# objects (models)](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.0#bind-to-a-class) and then make them available for consumption by our application using the [`IOptions`](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.options.ioptions-1?view=aspnetcore-3.0) interface.   

By using [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection), we can conveniently insert these populated models into the constructor of classes as required.   If you are familiar with the subject of unit testing, you will appreciate that this is a very good thing.

Benefits of this way of working include:
 
* It's super easy to organise/group related configuration items together, by using [hierarchy](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.0#hierarchical-configuration-data) to nest them under a parent item in the config file.
* The configuration binding code can typically be confined to a single place in our project (e.g. the startup class), avoiding code sprawl.
    * [String literal](https://jonskeet.uk/csharp/strings.html#literals) bugs (e.g. the silly mistakes that we all make, such as typo's in a key name) are reduced or even avoided.  Where they are a problem, they tend to show up sooner in the development process.  This is because an error in a centralised part of the codebase tends to be noticed quickly, because it usually impacts many parts of our application.  This is when compared to having our wider codebase littered with references to configuration that rely on string literal values.

* When we start working with strongly-typed configuration objects, rather than crude string values, we can then start to do useful things such as using dependency injection to insert populated configuration models into our consuming code.    

> We'll examine the actual code for all of this, in [part 3 of this series](https://blogs.siliconorchid.com/post/coding-inspiration/azure-function-configuration/part3-aspnet-in-functions/)

<br/>

> **Update Nov2019** : Shortly after publishing this article, [Steve Collins](https://twitter.com/stevetalkscode) of [stevetalkscode.co.uk](http://stevetalkscode.co.uk/) reached out, as he has recently been speaking and blogging about the subject of configuration himself.   You can find his [slide deck here]
(https://t.co/HM0J3voVVS).   You may find it useful to explore his blog about [configuration-bridging](http://stevetalkscode.co.uk/configuration-bridging-part-1), as it covers the subject of using `IOptions<>` compared to directly binding an object to configuration. 


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

In part 2 of this series, we look at how configuration in *Azure Function* works and talk about some of the issues.

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