question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

AddSystemsManager breaks other Json providers

See original GitHub issue

Description

When using AddSystemsManager after other providers based on JSON, the other provider is executed twice, throwing an exception.

Reproduction Steps

  1. Create a console project with the following package references
<PackageReference Include="Amazon.Extensions.Configuration.SystemsManager" Version="2.1.0" />
<PackageReference Include="Kralizek.Extensions.Configuration.Objects" Version="1.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="5.0.0" />
  1. Add the following code in Program.cs (relevant namespaces missing)
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddObject(new { Foo = "Bar" }, "Test");
configurationBuilder.AddSystemsManager($"/some/key/to/import");
var configuration = configurationBuilder.Build();

The following exception was thrown: System.FormatException: 'A duplicate key 'Test:Foo' was found.'

  1. The same doesn’t happen when:
  • configurationBuilder.AddSystemsManager($"/some/key/to/import"); is commented out
  • configurationBuilder.AddSystemsManager($"/some/key/to/import"); is placed before configurationBuilder.AddObject(new { Foo = "Bar" });
  • two calls to AddObject are added with different objects:
configurationBuilder.AddObject(new { Foo = "Bar" }, "Test");
configurationBuilder.AddObject(new { Hello = "World" }, "Test");

Logs

System.FormatException
  HResult=0x80131537
  Message=A duplicate key 'Test:Foo' was found.
  Source=Kralizek.Extensions.Configuration.Objects
  StackTrace:
   at Kralizek.Extensions.Configuration.Internal.JsonConfigurationSerializer.VisitPrimitive(JValue data)
   at Kralizek.Extensions.Configuration.Internal.JsonConfigurationSerializer.VisitToken(JToken token)
   at Kralizek.Extensions.Configuration.Internal.JsonConfigurationSerializer.VisitJObject(JObject jObject)
   at Kralizek.Extensions.Configuration.Internal.JsonConfigurationSerializer.Serialize(Object source, String rootSectionName)
   at Kralizek.Extensions.Configuration.Internal.ObjectConfigurationProvider.Load()
   at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList`1 providers)
   at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
   at ConfigurationSample.Program.<Main>d__0.MoveNext() in C:\Users\RenatoGolia\Development\InsightArchitectures\samples\ConfigurationSample\Program.cs:line 26
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at ConfigurationSample.Program.<Main>(String[] args)

  This exception was originally thrown at this call stack:
    Kralizek.Extensions.Configuration.Internal.JsonConfigurationSerializer.VisitPrimitive(Newtonsoft.Json.Linq.JValue)
    Kralizek.Extensions.Configuration.Internal.JsonConfigurationSerializer.VisitToken(Newtonsoft.Json.Linq.JToken)
    Kralizek.Extensions.Configuration.Internal.JsonConfigurationSerializer.VisitJObject(Newtonsoft.Json.Linq.JObject)
    Kralizek.Extensions.Configuration.Internal.JsonConfigurationSerializer.Serialize(object, string)
    Kralizek.Extensions.Configuration.Internal.ObjectConfigurationProvider.Load()
    Microsoft.Extensions.Configuration.ConfigurationRoot.ConfigurationRoot(System.Collections.Generic.IList<Microsoft.Extensions.Configuration.IConfigurationProvider>)
    Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
    ConfigurationSample.Program.Main(string[]) in Program.cs
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
    ...
    [Call Stack Truncated]

I realize that the error occurs in the other library, but I created this issue because the error occurs when AddSystemsManager is added after the other provider.

Environment

  • Build Version: 2.1.0
  • OS Info: Windows 10
  • Build Environment: dotnet run
  • Targeted .NET Platform: net 5.0

Resolution

  • 👋 I can/would-like-to implement a fix for this problem myself

I suspect the provider behind AddSystemsManager somehow executes other providers again but I couldn’t find the source of the bug.


This is a 🐛 bug-report

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:6 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
Kralizekcommented, Jun 10, 2021

Thanks @KenHundley for your quick reply. I’ll look into the change you suggested 😃

1reaction
KenHundleycommented, Jun 9, 2021

Hey @Kralizek, that’s correct that it does load some of the sources, depending on the situation. If you don’t directly supply the AWSOptions object to the AddSystemsManager call then it’ll build the previous sources in a attempt discover the necessary AWS configuration data, like profile, region, etc.

For example:

builder.AddCommandLine(args);
builder.AddEnvironmentVariables();
builder.AddSystemsManager($"/some/key/to/import");

will build the CommandLine and EnvironmentVariables sources and look for the necessary AWS configuration data. This happens here: SystemsManagerExtensions.cs Since the sources are executed in order they are added to the builder it always finds the ones above the AddSystemsManager call.

One way to solve this is to explicitly create the AWSOptions object and pass it to the AddSystemsManager call. Since the extenion has all that it needs it does not execute the previous sources.

builder.AddCommandLine(args);
builder.AddEnvironmentVariables();
builder.AddObject(new { Foo = "Bar" }, "Test");
var awsOptions = new AWSOptions { Profile = "test", Region = RegionEndpoint.USEast1 };
builder.AddSystemsManager($"/some/key/to/import", awsOptions);

Also, I have a suggestion for your https://github.com/Kralizek/ObjectConfigurationExtensions project. The issue is occuring because you are creating the json serializer object when the source is created and it has a class level variable in the serializer class that holds all previous data. If you were to move the seralizer creation to the load then you would also prevent this issue since the _data object wouldn’t already have the previous execution. image Since the load is only executed when the configuration is built it shouldn’t have any performance impact. btw, I did a quick test with this serializer change and the issue disappeared.

Read more comments on GitHub >

github_iconTop Results From Across the Web

C# AWS Parameter Store - Configuration not loading ...
It is always talking to appsettings.json. I tried debugging locally, still same behavior. Not able to find the SystemManagerConfiguration under ...
Read more >
NET Core configuration provider for AWS Systems Manager
This NuGet package simplifies how your application loads the application configuration settings in the AWS Systems Manager Parameter Store into ...
Read more >
Discovering AWS for .NET Developers
Learn a bit about how Amazon Web Services (AWS) supports .NET platforms including hosting ASP.NET Core apps.
Read more >
Configuring ASP.NET Core In AWS - Cold-Brewed DevOps
json file and the environment variables, CreateDefaultBuilder() sets up several configuration providers. According to the documentation, it sets ...
Read more >
C# (CSharp) AWSOptions Examples
C# (CSharp) AWSOptions - 37 examples found. These are the top rated real world C# (CSharp) examples of AWSOptions extracted from open source...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found