Confused old man

The day is a Friday. We were calmly deploying an app we tested locally to the test environment. The error we had was pointing towards the config files. Off we go to check the appsettings.json file…

Every value seems correct, but the error is definitely pointing us here. Here’s a simplified version of the offending line:

Console.Writeline(AConfig.ASubConfig);

And the corresponding appsettings:

{
    "AConfig" : {
        "ASubConfig" : []
    }
}

“But an empty array is not the same as a null value! And even if it was, it’s a value inside the “ASubConfig” property! There’s no way for this to be null!” was what I thought. And I thought wrong.

How the file is actually parsed

Actually, there’s a way for it to be null. Or at least, the JSON Provider which is gonna look at ours JSONs thinks so. Since .NET’s config system is ready to take in different providers, it was built with the common points of said providers in mind… And hierarchies aren’t one of those points.

What happens is that the JSON Provider’s parser is going to look at our JSON file and it’s going to map all those informations to a dictionary, in which every value is mapped with a key which corresponds to the path to that value in the file.

The “gotcha” here is in the way the arrays are processed: Each index of each array is processed as a part of the path. Meaning, that the following appsettings:

{
    "AnArray" : ["AThing", "AnotherThing", "AThirdThing"]
}

Will originate a dictionary with the following entries:

  • AnArray:0 = “AThing”
  • AnArray:1 = “AnotherThing”
  • AnArray:2 = “AThirdThing”

Why do empty arrays cause an issue?

What happens if the array is empty? Well, by convention, an empty array wont originate any entries in our dictionary… So, to the .NET binder which is gonna look at our dictionary, that array doesn’t exist at all.

Even moreso, as there is no value inside that array which we can map to some path, every object on top of it in the hierarchy won’t have any value we can map either, meaning those objects won’t exist themselves (assuming they don’t have any other properties with not null values).

In practice, our dictionary will be empty, our .NET binder won’t be able to map anything, and the number of “WTH”s per second will spike before lunch time.

TLDR: .NET’s config system treats any object in appsettings.json that does not have any value associated with it’s properties as if it didn’t exist, and the same happens if that value is an empty array.

If anyone wants to read more on this, here’s a link for the github issue where I found most of this information:

https://github.com/dotnet/extensions/issues/1341

Happy coding everyone!

LEAVE A REPLY

Please enter your comment!
Please enter your name here