Handling secrets in ASP.NET Core


Overview

BrowserPower is a simple game leveraging the power of Azure Cognitive Services - Vision API.  The premise is simple, given clues, find the best image from the web that matches it.  The clues might be a herd of sheep or a particular celebrity eating a cheeseburger.  The game itself is not as important as the technology used to create it.
This wiki highlights Configuration in ASP.Net Core.

Note: SendGrid was highlighted in a previous TechNet Wiki article.

Background

The game grew from the wiki article: Getting started with Cognitive Services - Vision.  Playing the game is simple: An internet search game using Azure Cognitive Services.  The project has been uploaded to MSDN as it is an interesting illustration of building an Asp.Net Core Azure Web App from the ASP.NET Core Web Application template and implements several of steps in the ASP.NET Core Tutorials.  
The source can be located here.

Configuration in ASP.Net Core

The configuration in ASP.Net supports an approach to combining multiple configuration providers into a single list of name-value pairs.  As an improvement over traditional ASP.Net, the configuration extension provides a mechanism for flexibly combining different configuration providers in order to abstract away configuration details from the rest of the application.  The following provides the supported configuration providers:

  • File formats (INI, JSON, and XML)
  • Command-line arguments
  • Environment variables
  • In-memory .NET objects
  • An encrypted user store
  • Azure Key Vault
  • Custom providers

In the BrowserPower project, a combination of JSON files (appsettings.json, secrets.json) and environment variables.  .Net Core has a nice feature to allow for the Safe storage of app secrets during development in ASP.NET Core.  In combination with the Secret Manager tool, this allows for the safe storage of sensitive data during development.  The following is an illustration of how the secrets are retrieved during startup and made available in the Configuration property:

public Startup(IHostingEnvironment env)
{
    var builder = new  ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
 
    if (env.IsDevelopment())
    {
        // For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709
        builder.AddUserSecrets();
    }
 
    builder.AddEnvironmentVariables();
    Configuration = builder.Build();
}

In BrowserPower, the secrets.json file contains a collection of configuration items including SendGrid, Cognitive Services and Azure Storage keys:

There are several ways to retrieve the configuration values once they are loaded.  One way would be to retrieve directly from the collection:

public void  ConfigureServices(IServiceCollection services)
{
    _testSecret = Configuration["MySecret"];
}

Another example during Startup of the .Net Core application is when the services are added to the container.  For example, the Emotion and Vision Cognitive Services are added as follows:

public void  ConfigureServices(IServiceCollection services)
{
...
     services.Configure<CognitiveServiceOptions>(Configuration);
}

This injects the configuration object (CognitiveServiceOptions) into the constructor of the service as shown below:

public class  CognitiveService : ICognitiveService
{
    public bool  RunSequentially => CognitiveServiceOptions.RunSequentially;
 
    public CognitiveServiceOptions CognitiveServiceOptions {  get; set; }
 
    public CognitiveService(IOptions<CognitiveServiceOptions> options)
    {
        CognitiveServiceOptions = options.Value;
 
    }
...
}

For completion, here is a definition of the CognitiveServiceOptions class:

public class  CognitiveServiceOptions
{
    public bool  RunSequentially { get; set; }
    public CognitiveServiceOption EmotionApi { get; set; }
    public CognitiveServiceOption VisionApi { get; set; }
}
 
public class  CognitiveServiceOption
{
    public string  BaseUrl { get; set; }
    public string  ApiKey { get; set; }
}

The secrets.json file will not be deployed to production, instead Azure Key Vault is recommended.  As BrowserPower is an Azure Web app, the AppSettings was used (Note the colon in the complex configuration items):  

Conclusion

.Net Core offers mature mechanisms for managing configuration.  Configuration, Microsoft.Extensions.Configuration, supports multiple configuration providers with built-in support for multiple development environments.  Microsoft Documentation is the first place to go to see clear definitions and examples of the different aspects of configuration in .Net Core.