21

User Secrets error is being generated in a CI/CD pipeline, when secrets.json file shouldn't be expected.

Steps:

  1. Create .NET 5 project
  2. Added user secrets.
  3. Code runs locally and in CI/CD pipelines.
  4. Upgrade to .NET 6 project (and preview NuGet 6.* packages)

Code runs locally, but fails in CI/CD pipelines, with error:

"The configuration file 'secrets.json' was not found and is not optional."

Expected:

Code runs without the secrets.json file being present Configuration .NET 6, Microsoft.Extensions.Configuration.UserSecrets: 6.0.0-preview.1.21102.12

Regression? This works in .NET 5, Microsoft.Extensions.Configuration.UserSecrets: 5.0.0.*

System.IO.FileNotFoundException: The configuration file 'secrets.json' was not found and is not optional. The physical path is '/home/runner/work/UserSecretsRegression/UserSecretsRegression/UserSecrets/UserSecrets.Tests/bin/Release/net6.0/secrets.json'.
  Stack Trace:
      at Microsoft.Extensions.Configuration.FileConfigurationProvider.HandleException(ExceptionDispatchInfo info)
   at Microsoft.Extensions.Configuration.FileConfigurationProvider.Load(Boolean reload)
   at Microsoft.Extensions.Configuration.FileConfigurationProvider.Load()
   at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList`1 providers)
   at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
   at UserSecrets.Tests.UnitTest1.TestMethod1() in /home/runner/work/UserSecretsRegression/UserSecretsRegression/UserSecrets/UserSecrets.Tests/UnitTest1.cs:line 13
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Mehdi Daustany
  • 1,018
  • 4
  • 10
  • 23
  • 1
    Unit tests should never depend on secrets (they are a dev machine feature only). Can you paste the start of the unit test that configures the ConfigurationBuilder? – Neil Nov 21 '21 at 17:47
  • Thanks, yep I know, that's just an example – Mehdi Daustany Nov 22 '21 at 09:31
  • Your stack trace shows a path that is not a 'secrets.json' path. User secrets are stored in `%UserProfile%\AppData\Roaming\Microsoft\UserSecrets\\secrets.json`. Is it possible that someone has added a direct reference to the secrets file, and then set that file to be 'Content'/'Copy to output' ? – Neil Nov 22 '21 at 10:58

3 Answers3

50

https://github.com/dotnet/runtime/issues/48485

Basically, it's a new feature in .NET6 that 'secrets.json' is not optional by default!

AddUserSecrets(this IConfigurationBuilder configuration, Assembly assembly, bool optional);

That 'optional' parameter should be set to 'true' in your code.

 var configuration = new ConfigurationBuilder()
    .AddEnvironmentVariables()
    .AddCommandLine(args)
    .AddJsonFile("appsettings.json")
    .AddUserSecrets<Program>(true)
    .Build();
Greg Gum
  • 33,478
  • 39
  • 162
  • 233
Neil
  • 11,059
  • 3
  • 31
  • 56
5

Unlike environment variables, user secrets are placed in a settings file similar to appsettings.json. Having similar structured off-project settings is great when you need to copy keys and values between files and there is support for adding, removing, and listing values as I will show you later in this post.

To understand user secrets, let's resume the example from the previous post. In there I had an appsettings.json file looking like this:

{
  "AppSettings": {
    "ConnectionString": "http://localhost:9000"
  },
  ...
}

In order to override the AppSettings:ConnectionString setting on individual machines, each user needs to add a user secret with the same name. The easiest approach is to right-click the project and select Manage User Secrets:

enter image description here

This creates and opens a new empty JSON file named secrets.json. The file is placed beneath C:\Users\<username>\AppData\Roaming\Microsoft\UserSecrets\<id> where <username> matches your Windows user and is a randomly generated GUID. The important thing to notice here is that the file is located outside your project directory. In order to "bind" the secrets.json file location to your project, Visual Studio added a bit of markup to the csproj file:

<PropertyGroup>
  <UserSecretsId>dda25df4-9a88-4a7e-8502-2134b74e4729</UserSecretsId>
</PropertyGroup>

In case you are not using Visual Studio, you can generate a random GUID and add the <UserSecretsId> manually.

In case you want to override the AppSettings:ConnectionString setting, add a similar structure to the secrets.json file:

{
  "AppSettings": {
    "ConnectionString": "http://localhost:9000?user=mehdidaustany&password=1234"
  }
}

You can also collapse settings like this:

{
  "AppSettings:ConnectionString": "http://localhost:9000?user=mehdidaustany&password=1234"
}

Finally add created secrets.json in the root of your project.

Mehdi Daustany
  • 1,018
  • 4
  • 10
  • 23
  • Thanks for the tip. For me, though, it was after I upgraded my VS2022 to the latest version 17.2.5 it automatically created an entry in project property (the project was already in .Net 6.0): dda25df4-9a88-4a7e-8502-2134b74e4729 I unloaded the project, then deleted the entry and that fixed the issue. I already have all the secrets stored in a local setting file, so no need for more place to stow secrets that are not supposed to be checked in to Git repo. – Stevey Jun 23 '22 at 22:54
4

In .net 6.0, the application needs secret.json to run. in any case, if you are migrating from .net core 3.1 or .net 5.0 in order to run your application in .net 6.0:

  1. run dotnet user-secrets init in your project folder using command-line tools.
  2. make sure you have a secret.json file in your app domain ...\bin\Debug\net6.0. It doesn't matter if your secret.json file is empty for now.

Hit F5 and run your application!

  • 2
    my beef about secrets.json is that the file tends to disappear completely (VS2022) and this did not happen in VS2019, I believe there is a bug in VS2022 – MC9000 Apr 06 '22 at 02:25
  • @MC9000 This happened to me in VS2019. It had something to do with my coworkers checking in their code and me pulling it down. Same thing would happen on my coworkers end. It might be something with `` property being overwritten in the project file. – Lukas Mar 02 '23 at 16:31