2

I have an ApplicationConfigurationSettings class which I am binding the values from the appsettings.json file to. I can get everything bound except the logger LogLevel value, most likely due to the existence of a sub level in the json format of Logging entry.

I bind the class as follows

 services.Configure<ApplicationConfigurationSettings>(Configuration.GetSection("ApplicationConfiguration"));

appsettings.json (parts removed for brevity)

{
   "ApplicationConfiguration": {
      "ConnectionStrings": {
         "DevelopmentConnection": "Server=(localdb)\\mssqllocaldb;Database=TestingConfigurationNetCoreTwo_Development;Trusted_Connection=True;MultipleActiveResultSets=true"       
        },
        "Logging": {
           "IncludeScopes": false,
           "LogLevel": {
              "Default": "Warning"
         }
       },
       "ApplicationIconUrls": {
           "MaleUserIcon": "https://machineryrestorations.blob.core.windows.net/publicfiles/images/BestMaleUser_32x32.png",
           "FemaleUserIcon": "https://machineryrestorations.blob.core.windows.net/publicfiles/images/BestFemaleUser_32x32"
      },   
      "ApplicationInfo": {
          "VersionNumber": "1.0.0",
          "Author": "Jimbo",
          "ApplicationName": "CustomTemplate",
          "CreatedOn": "November 20, 2017"

        }
    }
}

My logger POCO

public class LoggerSettings
{
    public bool IncludeScopes { get; set; }
    public KeyValuePair<string,string> LogLevel { get; set; }
}

I'm sure it is due to the fact that the binder can't reconcile my LogLevel property with what is in the json file. How can I change my logger POCO to get this to work since I cannot change the Logging format in the json file?

This is how the json provider resolves it when inspecting Configuration from

services.AddSingleton(Configuration);

{[ApplicationConfiguration:Logging:IncludeScopes, False]} {[ApplicationConfiguration:Logging:LogLevel:Default, Warning]}

I just can't seem to set that property up properly in the class so it binds correctly.

1 Answer 1

1

Json object

"LogLevel": {
  "Default": "Warning"
}

could not be mapped to public KeyValuePair<string,string> LogLevel { get; set; } property for a simple reason. What if some time after, the section will be extended with another fields:

"LogLevel": {
  "Default": "Warning",
  "SomeOtherField": "SomeValue"
}

How should it be mapped to single KeyValuePair<string,string>? Of course, in your simple case such single key-value object could be potentially mapped, but configuration binder does not go so far in its assumptions, it just does not work in this way.

And I believe it's a good thing because you're trying to shift from strongly-typed POCO to some bag of key-values, it devalues in some degree the whole approach of strongly-typed configuration taken in .net core.

The fix of your problem is quite simple. Just declare LoggingLevel class with single (for this moment) property Default of string type:

public class LoggingLevel
{
    public string Default { get; set; }
}

public class LoggerSettings
{
    public bool IncludeScopes { get; set; }

    public LoggingLevel LogLevel { get; set; }
}

You could go a little further and set the type for Default property as Microsoft.Extensions.Logging.LogLevel. Configuration binder will correctly map string value like "Warning" to enum value LogLevel.Warning:

public class LoggingLevel
{
    public LogLevel Default { get; set; }
}

It could seem an overkill to have such simple POCO, and you will have quite a lot of them for advanced configurations. But that's actually the way to go, strongly-typed, explicit and extensible.

Sign up to request clarification or add additional context in comments.

2 Comments

ty, but asyou may have realized after answering my Serilog question, I switched to using Serilog. I will be using typed poco's there so this answer certainly helps me in that regard
@CodeFuller...wanna go for three in a row? I have another Serilog question posted here...stackoverflow.com/questions/47540478/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.