Managing Application Secrets in Azure App Configuration Service with .NET Core Code Walkthrough

  1. Introduction into managing Application Secrets in Azure App Configuration Service with .NET Core (previous)
  2. Managing Application Secrets in Azure App Configuration Service with .NET Core Code Walkthrough (current post)

In the previous post I introduced various ways of storing secrets. In this post I’ll walk through the code required to pull out settings from User Secrets when running in development as well as from the Azure App Configuration Service when running in production.

In order to leverage User Secrets and Azure App Configuration Service in .NET Core it is necessary to add references to the following nuget packages:

The csproj that contains the main entry point to load the strongly typed configuration requires the UserSecretId defined like show below

<PropertyGroup>
  <UserSecretsId>GuidOfYourChoice</UserSecretsId>
</PropertyGroup>

Once that is in place it is possible to add the User Secrets for the development environment like shown below

hostBuilder.ConfigureAppConfiguration((hostContext, config) => {
   if (hostContext.HostingEnvironment.IsDevelopment())                          
   {
      config.AddUserSecrets<Program>();
   }
})

After adding the User Secrets it is required to add the options to the service collection as well as bind strongly typed settings.

hostBuilder.ConfigureServices((hostContext, services) => {
   services.AddOptions();
   // omited...
   services.Configure<MySettings>settings.GetSection("MySettings"));
})
public class MySettings {
   public string FirstValue { get; set; }
   public bool SecondValue { get; set; }
}

To store settings in the User Secrets store open a Powershell command line in the same folder as the csproj that has the UserSecretId specified and type

dotnet user-secrets set MySettings:FirstValue Development
dotnet user-secrets set MySettings:SecondValue true

To list the currently stored User Secrets type

PS C:\p\AzureAppConfigurationDemo> dotnet user-secrets list
MySettings:SecondValue = true
MySettings:FirstValue = Development

Any component that would like to read the settings can inject MySettings over the IOptionsXYZ<T> interfaces. Below is a snippet that shows a hosted service that injects IOptionsMonitor<T> which allows to observe the settings for changes.

class MyHostedService : IHostedService {
   private readonly IOptionsMonitor<MySettings> optionsMonitor;
   private IDisposable subscription;

   public MyHostedService(IOptionsMonitor<MySettings> optionsMonitor) {
            this.optionsMonitor = optionsMonitor;
   }
   public Task StartAsync(CancellationToken cancellationToken) {
      var settings = optionsMonitor.CurrentValue;
      Console.WriteLine(settings.FirstValue);
      Console.WriteLine(settings.SecondValue);

      subscription = optionsMonitor.OnChange(MySettingsChanged);
      return Task.CompletedTask;
   }

   private void MySettingsChanged(MySettings arg1, string arg2) {
      Console.WriteLine(arg2);
      Console.WriteLine(arg1.FirstValue);
      Console.WriteLine(arg1.SecondValue);
    }

    public Task StopAsync(CancellationToken cancellationToken) {
       subscription.Dispose();
       return Task.CompletedTask;
   }
}

When we run this using dotnet run we’ll see the following output

Output using the UserSecrets

Now that’s working let’s plug in the App Configuration Service. I’m going to walk through how to set up the service itself. It is literally just creating a new service in the resource group of your choice. Once that is set up you need the connection string available under the Access Keys page to be able to connect to it. To make things work we have to add the following code to ConfigureAppConfiguration:

if (!hostContext.HostingEnvironment.IsDevelopment()) {
    var settings = config.Build();
    config.AddAzureAppConfiguration(o => o.Connect(settings.GetConnectionString("AppConfig"))
        .Use("*", labelFilter: hostContext.HostingEnvironment.EnvironmentName)
        .Watch("MySettings:FirstValue", label: hostContext.HostingEnvironment.EnvironmentName, TimeSpan.FromSeconds(5)));
}

This fetches the connection string from the environment variable CUSTOMCONNSTR_APPCONFIG in the any environment that is not development and sets up a watcher to observe MySettings:FirstValue every five seconds and reload it when it changes. Multiple .Watch calls can be chained together to selectively observe and reload properties or it is possible to use WatchAndReloadAll to reload all configuration settings when a certain property changes. The .Use call with the label filter makes sure only relevant configuration entries for the environment are loaded from the service.

Labeled entries in App Configuration Service

So given the above entries in the App Configuration service changing the environment leads to different outputs.

Different configuration depending on the environment

With the monitor setup every time the value changes in a given environment the configuration layer automatically reloads the configuration

Configuration changes are reflected without restarts

The new configuration layer available with ASPNET Core hosting as well as the Generic Host in combination with App Configuration Service provides a really powerful way of storing application secrets. The sample code in this blog post can be found on my github account under AzureAppConfigurationDemo.

About the author

Daniel Marbach

Add comment

Recent Posts