Visual Studio - User Secrets






4.84/5 (13 votes)
Provides a developer’s overview on how to get started with using Visual Studio’s User Secrets
Purpose
I’d like to take a lot of the legwork out for developers, when investigating a new feature like User Secrets.
Covering relevant topics such as overriding appsettings.json files, loading the appropriate appsetting based on the environment (Development for e.g.), how to add\update your secrets.
Scope
The scope of this document is to convey the tasks required to secure sensitive information locally and not within a team code repository (for e.g., a connection string to your LocalDB, which shows your password).
Prerequisites
- Visual Studio 22 (community edition)
- .NET 6 SDK (this can be bundled with VS 22 installation)
- SQL Server 2019 Developer Edition
Why use User Secrets – What Problem Does it Solve
Usually, the settings are placed in the appsettings.json file, but there are settings that we don’t want to share in this file, like passwords, usernames or fully qualified connection strings.
So, the user secrets are used for that, when we only want secrets to be visible to me on my environment.
Create a Console Project
We’ll demonstrate how User Secrets works by implementing a simple Console .NET 6 application.
The new layout of the Console .NET 6 project you will be presented with just a Program.cs with no plumbing in place – here, we will add the code needed:
Add UserSecrets NuGet Package to Project
Add the following NuGet package to your project:
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets"
Version="6.0.1" />
This will, in turn, create an entry in your project properties file called UserSecretsId
:
This GUID entry is used to build up the path to the newly created file named secrets.json in your (windows) environment. You won’t see the file inside the solution explorer as it’s saved within your roaming data. The physical path to your secrets.json file (not included in your code check-in) is:
C:\Users\oneillb\AppData\Roaming\Microsoft\UserSecrets\
050d3b82-cafe-4826-93ed-e156a0ec77be\
Open User Secrets
Right click on your project and select the context menu option Manage User Secrets.
This will open your secrets.json file. Initially, your secrets will be empty, as you have yet to create any entries.
The trick is to keep the same json structure in both the secrets.json and appsettings.json file
Appsettings.json (Development or Production)
Secrets.json
Thus, when you reference the settings, it doesn’t matter which json file is loaded, the composite key will be valid.
Register Appsetting and User Secrets at Start-Up
In the snippet of code below (in your Program.cs file), you are creating what would have been the Configuration
method to register your pipeline objects (middleware, dependency injection, for e.g.)
The order that you load your settings in is important, as the last setting referenced will be the one that gets used (last in wins – if two appsetting files get loaded and they both have a common connection string, the last loaded, that connection string will get used.)
In the code above, I am building up one of the Appsetting files, based on the runtime environment setting – see how it is set below (to Development):
NB: If your Appsetting file doesn’t exist – no exception is thrown!
A side note, I am retrieving the Environment
variable using the snippet of code below – this is then used to build up the Appsetting file name that I wish to import (I don’t have to import this specific Appsetting – I could load production and override it with my User Secrets).
If I just want to referencing User Secrets in my code:
Reading User Secret Values - Runtime
Once I have loaded the Appsetting and\or User Secrets, and because I have the same json key\value structure within the file, I can make the reference one and it will load the correct setting. There are a couple of ways that I can load the value based on a key.
Retrieving and setting the return type (using the fully qualified json structure):
string fullyQualifiedConnectionString =
config.GetValue<string>("ConnectionStrings:MyMusicShopConnection"); // read connection
Retrieving a value using the fully qualified json structure:
var fullyQualifiedConnectionStringShortHand =
config["ConnectionStrings:MyMusicShopConnection"];
Retrieving a value using the section qualifier (GetConnectionString
):
var conString = config.GetConnectionString("MyMusicShopConnection");
Retrieving a root level value:
var userId = config["UserID"]; // no parent & shorthand
Snippet of code used:
Revision History
- 27th May, 2022: Initial draft (v1)
- 30th May, 2022: Update - additional topics (v2)