dinotom
dinotom

Reputation: 5162

Binding logging configuration from appsettings to POCO Asp.Net Core 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.

Upvotes: 2

Views: 1995

Answers (1)

CodeFuller
CodeFuller

Reputation: 31282

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.

Upvotes: 1

Related Questions