Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a POCO class to .NET Core configuration

I am working on integration tests of .NET Core application and want to use some test configuration. My configuration is a POCO class that is configured via appsettings.json and then consumed via IOptions<T>. In my tests I'd like to use an instance of that class.

Here is the code:

 var mySettings = GetTestSettings(); // factory method returning POCO class 
 var configurationBuilder = new ConfigurationBuilder();

 // I am looking for something like 
 configurationBuilder.AddInMemoryObject("Settings", mySettings);

 // does not work, result is just string 
 configurationBuilder.AddInMemoryCollection("Settings",
        JsonConvert.SerializeObject(mySettings)); 

// requires filename
configurationBuilder.AddJsonFile("filename.json");

What is the easiest way to feed POCO to configuration?

like image 271
the_joric Avatar asked Mar 20 '18 11:03

the_joric


People also ask

What is IConfiguration in .NET core?

The IConfiguration is an interface for . Net Core 2.0. The IConfiguration interface need to be injected as dependency in the Controller and then later used throughout the Controller. The IConfiguration interface is used to read Settings and Connection Strings from AppSettings. json file.

What is launchSettings json in .NET core?

The launchSettings. json file is used to store the configuration information, which describes how to start the ASP.NET Core application, using Visual Studio. The file is used only during the development of the application using Visual Studio. It contains only those settings that required to run the application.


1 Answers

AddInMemoryCollection takes a collection of KeyValuePair where a key is setting key and value is its value. This call from the question

configurationBuilder.AddInMemoryCollection("Settings", JsonConvert.SerializeObject(mySettings));

actually passes "Settings" as a key and whole JSON as one setting value, which expectedly does not work.

But the overall approach is correct, you should use AddInMemoryCollection extension call. In collection passed to this call, setting keys are full paths within configuration, delimited by a colon. Say if you have following settings POCO:

public class SomeSettings
{
    public string SomeKey1 { get; set; }
    public int SomeKey2 { get; set; }
}

and it's loaded from following JSON

{
    "SomeSettings": {
        "SomeKey1": "SomeData",
        "SomeKey2": 123
    } 
}

the keys would be SomeSettings:SomeKey1 and SomeSettings:SomeKey2.

You could then add such configuration with following AddInMemoryCollection call:

configurationBuilder.AddInMemoryCollection(new Dictionary<string, string>
{
    { "SomeSettings:SomeKey1", "SomeData" },
    { "SomeSettings:SomeKey2", 123 },
});

Now, if you want to add settings POCO with one call, you could write simple extension method that will enumerate setting class properties using reflection and return collection of key-value pairs for properties names and values.

Here is a sample:

public static class ObjectExtensions
{
    public static IEnumerable<KeyValuePair<string, string>> ToKeyValuePairs(this Object settings, string settingsRoot)
    {
        foreach (var property in settings.GetType().GetProperties())
        {
            yield return new KeyValuePair<string, string>($"{settingsRoot}:{property.Name}", property.GetValue(settings).ToString());
        }
    }
}

public static class ConfigurationBuilderExtensions
{
    public static void AddInMemoryObject(this ConfigurationBuilder configurationBuilder, object settings, string settingsRoot)
    {
        configurationBuilder.AddInMemoryCollection(settings.ToKeyValuePairs(settingsRoot));
    }
}

In the test:

var configurationBuilder = new ConfigurationBuilder();
var mySettings = GetTestSettings();
configurationBuilder.AddInMemoryObject(mySettings, "Settings");

Such simple ObjectExtensions.ToKeyValuePairs extension method will work for plain POCO like SomeSettings above. However it will not work if some of the properties are also objects like here:

public class InnerSettings
{
    public string SomeKey { get; set; }
}

public class OuterSettings
{
    public InnerSettings InnerSettings { get; set; }
}

However I believe you got an idea and could make required adjustments if required.

like image 64
CodeFuller Avatar answered Sep 23 '22 14:09

CodeFuller