Skip to content
Bruno Sonnino
Menu
  • Home
  • About
Menu

Storing values in the Secret Manager tool

Posted on 2 October 2022

When you are developing a new project and need to store settings for it, the first thing that comes to mind is to use the Appsettings.json file. With this file, you can store all settings in a single file and restore them easily.

For example, let's create a console project that has three settings: Id, Name and Version. In a command line prompt, type:

dotnet new console -o SecretStorage
cd SecretStorage
code .
PowerShell

This will open VS Code in the folder for the new project. Add a new file named appSettings.json and add this code in it:

{
    "AppData": {
        "Id": "IdOfApp",
        "Name": "NameOfApp",
        "Version": "1.0.0.0"
    }
}
JSON

We will add a AppData class in the project:

public class AppData
{
    public string Id { get; init; }
    public string Name { get; init; }
    public string Version { get; init; }

    public override string ToString()
    {
        return $"Id: {Id}, Name: {Name}, Version: {Version}";
    }
}
C#

To read the settings into the class, we could use JsonDeserializer from System.Text.Json:

using System.Text.Json;

var settingsText = File.ReadAllText("appsettings.json");
var settings = JsonSerializer.Deserialize<Settings>(settingsText);
Console.WriteLine(settings);
C#

You need to define a class Settings to read the data:

public class Settings
{
    public AppData AppData { get; set; }
}
C#

That's fine, but let's say you have different settings for development and production, you should have a copy of the appsettings.json with the modified values and some code like this one:

using System.Diagnostics;
using System.Text.Json;

string settingsText; 
if (Debugger.IsAttached)
{
    settingsText = File.ReadAllText("appsettings.development.json");
}
else
{
    settingsText = File.ReadAllText("appsettings.json");
}
var settings = JsonSerializer.Deserialize<Settings>(settingsText);
Console.WriteLine(settings);
C#

Things start to become complicated. If there was a way to simplify this... In fact, yes there is. .NET provides us with the ConfigurationBuilder class. With it, you can read and merge several files to get the configuration. The following code will merge the appsettings.json and appsettings.development.json into a single class. In production, all you have to do is to remove the appsettings.development.json from the package and only the production file will be used.

To use the ConfigurationBuilder class you must add the NuGet packages Microsoft.Extensions.Configuration and Microsoft.Extensions.Configuration.Binder with

dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.Binder
PowerShell

You will also have to add the Microsoft.Extensions.Configuration.Json package to use the AddJsonFile extension method.

One other thing that you will have to do is to tell msbuild to copy the settings file to the output directory. This is done by changing the csproj file, adding this clause

<ItemGroup>
  <Content Include="appsettings*.json">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </Content>  
</ItemGroup>
XML

Once you do that, this code will read the config files, merge them and print the settings:

IConfigurationRoot config = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json", false)
    .AddJsonFile("appsettings.development.json", true)
    .Build();
var appdata = config.GetSection(nameof(AppData)).Get<AppData>();
Console.WriteLine(appdata);
C#

The second parameter in the AddJsonFile method tells that the appsettings.development.json file is optional and, if it's not there, it wont be read. One other advantage is that I don't need to duplicate all settings. You just need to add the overridden settings in the development file and the other ones will still be available.

Now, one more problem: let's say we are using an API that requires a client Id and a client Secret. These values are very sensitive and they cannot be distributed. If you are using a public code repository, like GitHub, you cannot add something like this to appsettings.json and push your changes:

{
    "AppData": {
        "Id": "IdOfApp",
        "Name": "NameOfApp",
        "Version": "1.0.0.0"
    },
    "ApiData": {
        "ClientId": "ClientIdOfApp",
        "ClientSecret": "ClientSecretOfApp"
    }
}
JSON

That would be a real disaster, because your API codes would be open and you would end up with a massive bill at the end of the month. You could add these keys to appsettings.development.json and add it to the ignored files, so it wouldn't be uploaded, but there is no guarantee that this won't happen. Somebody could upload the file and things would be messy again.

The solution, in this case, would be to use the Secret Manager Tool. This tool allows you to store secrets in development mode, in a way that they cannot be shared to other users. This tool doesn't encrypt any data and must only be used for development purposes. If you want to store the secrets in a safe encrypted way, you should use something like the Azure Key Vault.

To use it, you should initialize the storage with

dotnet user-secrets init
PowerShell

This will initialize the storage and generate a Guid for it and add it to the csproj file:

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <UserSecretsId>fc572277-3ded-4467-9c46-534a075f905b</UserSecretsId>
  </PropertyGroup>
XML

Then, you need to add the package Microsoft.Extensions.Configuration.UserSecrets:

dotnet add package Microsoft.Extensions.Configuration.UserSecrets
PowerShell

We can now start utilizing the user secrets, by adding the new configuration type:

IConfigurationRoot config = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json", false)
    .AddJsonFile("appsettings.development.json", true)
    .AddUserSecrets<Settings>()
    .Build();
C#

Then, we can add the secret data:

dotnet user-secrets set "ApiData:ClientId" "ClientIdOfApp"
dotnet user-secrets set "ApiData:ClientSecret" "ClientSecretOfApp"
PowerShell

As you can see, the data is flattened in order to be added to the user secrets. You can take a look at it by opening an Explorer window and going to %APPDATA%\Microsoft\UserSecrets\{guid}\secrets.json:

{
  "ApiData:ClientId": "ClientIdOfApp",
  "ApiData:ClientSecret": "ClientSecretOfApp"
}
JSON

As you can see, there isn't any secret here, it's just a way to store data with no possibility to share it in an open repository.

You can get the values stored with

dotnet user-secrets list
PowerShell

To remove some key from the store, you can use something like

dotnet user-secrets remove ClientId
PowerShell

And to clear all data, you can use

dotnet user-secrets clear
PowerShell

If you have some array data to store, you will have to flatten in the same way, using the index of the element as a part of the name. For example, if you have something like

public class Settings
{
    public AppData AppData { get; set; }
    public ApiData ApiData { get; set; }
    public string[] AllowedHosts { get; set; }
}
C#

You can store the AllowedHosts data with

dotnet user-secrets set "AllowedHosts:0" "microsoft.com"
dotnet user-secrets set "AllowedHosts:1" "google.com"
dotnet user-secrets set "AllowedHosts:2" "amazon.com"
PowerShell

And you can read the settings with some code like this:

IConfigurationRoot config = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json", false)
    .AddJsonFile("appsettings.development.json", true)
    .AddUserSecrets<Settings>()
    .Build();
var settings = config.Get<Settings>();
foreach (var item in settings.AllowedHosts)
{
    Console.WriteLine(item);
}
Console.WriteLine(settings.AppData);
Console.WriteLine(settings.ApiData);
C#

As you can see, if you need something to keep your development data safe from uploading to a public repository, you can use the user secrets in the same way you would do by using a json file. This simplifies a lot the storage of config files and allows every developer to have their own settings.

The full source code for this project is at https://github.com/bsonnino/SecretStorage

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

  • May 2025
  • December 2024
  • October 2024
  • August 2024
  • July 2024
  • June 2024
  • November 2023
  • October 2023
  • August 2023
  • July 2023
  • June 2023
  • May 2023
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • June 2022
  • April 2022
  • March 2022
  • February 2022
  • January 2022
  • July 2021
  • June 2021
  • May 2021
  • April 2021
  • March 2021
  • February 2021
  • January 2021
  • December 2020
  • October 2020
  • September 2020
  • April 2020
  • March 2020
  • January 2020
  • November 2019
  • September 2019
  • August 2019
  • July 2019
  • June 2019
  • April 2019
  • March 2019
  • February 2019
  • January 2019
  • December 2018
  • November 2018
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • November 2017
  • October 2017
  • September 2017
  • August 2017
  • June 2017
  • May 2017
  • March 2017
  • February 2017
  • January 2017
  • December 2016
  • November 2016
  • October 2016
  • September 2016
  • August 2016
  • July 2016
  • June 2016
  • May 2016
  • April 2016
  • March 2016
  • February 2016
  • October 2015
  • August 2013
  • May 2013
  • February 2012
  • January 2012
  • April 2011
  • March 2011
  • December 2010
  • November 2009
  • June 2009
  • April 2009
  • March 2009
  • February 2009
  • January 2009
  • December 2008
  • November 2008
  • October 2008
  • July 2008
  • March 2008
  • February 2008
  • January 2008
  • December 2007
  • November 2007
  • October 2007
  • September 2007
  • August 2007
  • July 2007
  • Development
  • English
  • Português
  • Uncategorized
  • Windows

.NET AI Algorithms asp.NET Backup C# Debugging Delphi Dependency Injection Desktop Bridge Desktop icons Entity Framework JSON Linq Mef Minimal API MVVM NTFS Open Source OpenXML OzCode PowerShell Sensors Silverlight Source Code Generators sql server Surface Dial Testing Tools TypeScript UI Unit Testing UWP Visual Studio VS Code WCF WebView2 WinAppSDK Windows Windows 10 Windows Forms Windows Phone WPF XAML Zip

  • Entries RSS
  • Comments RSS
©2025 Bruno Sonnino | Design: Newspaperly WordPress Theme
Menu
  • Home
  • About