Search code examples
wpf.net-6.0app-configclass-libraryconfigurationmanager

Creating classical Properties.Settings in .Net 6.0 (Core) "Class Library" projects


  • Created a new "WPF Application" .NET 6.0 project There creating classical Application Settings was easy in project->properties->Settings->"Create or open application settings"
  • Observed: the project gets a new folder "Properties" which has a yellow Folder icon with an additional black wrench symbol, okay
  • It contains a new item Settings.settings that can get edited via classical Settings Designer looking like it used to look in .Net 4.8, and a new App.config XML file is getting created automatically in the project's root folder which also looks like it used to in .Net 4.8, okay

Now the same procedure can apparently only be done manually in

  • a new "Class Library" project being added in the same solution where I would want to use that Properties.Settings / app.config feature pack for storing a DB connection string configurably:
  • the new sub-project does not seem to have a "Settings" option in the project Properties dialog (as opposed to a .Net4.x would have had)
  • the new Properties folder and new Settings file can be created successfully there too manually as described in Equivalent to UserSettings / ApplicationSettings in WPF .NET 5, .NET 6 or .Net Core
  • but doing a "Rebuild solution" gives an

Error CS1069 The type name 'ApplicationSettingsBase' could not be found in the namespace 'System.Configuration'. This type has been forwarded to assembly 'System.Configuration.ConfigurationManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' Consider adding a reference to that assembly. ClassLibrary1 C:\Users\Stefan\source\repos\WpfCorePropertiesSettings\ClassLibrary1\Properties\Settings.Designer.cs 16 Active

  • as a next step adding NuGet package "System.Configuration.Abstractions" to the Class Library project cures the symptom, "rebuild solution" makes the error disappear.

TLDNR, actual question: is that sequence an acceptable solution or a kludge to avoid?

To me the NuGet package description does not sound as if the package was made for that purpose, and I have not heard the maintainers' names before (which might or might not matter?) https://github.com/davidwhitney/System.Configuration.Abstractions

TIA

PS: "Class Library" Project Template

"Class Library" Project properties


Solution

  • In the meantime I'm happy with a custom "AppSettings.json" approach.

    After removing the previously described "classical app.config" approach, and after adding two NuGet packages:

    <PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
    

    ... I created a custom Json file on "Class Library" (sub)project level in Visual Studio manually, and set its CopyToOutputDirectory property

    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    

    And added an 'IConfigurationBuilder` part:

    using Microsoft.Extensions.Configuration;
    
    namespace Xyz.Data
    {
        internal class AppSettingsConfig
        {
            public AppSettingsConfig()
            {
                IConfigurationBuilder builder = new ConfigurationBuilder();
                _ = builder.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "AppSettings.Movies3Data.json"));
    
                var root = builder.Build();
                AttachedDb = root.GetConnectionString("AttachedDb")!;
            }
    
            public string AttachedDb { get; init; }
        }
    }
    

    And then made it a "Jon Skeet singleton"

        /// <summary>
        /// Singleton as described by Jon Skeet
        /// </summary>
        /// https://csharpindepth.com/Articles/Singleton
        internal sealed class AppSettingsConfigSingleton
        {
            private static readonly Logger log = LogManager.GetCurrentClassLogger();
    
            private AppSettingsConfigSingleton()
            {
                log.Trace($"{nameof(AppSettingsConfigSingleton)} ctor is running");
    
                IConfigurationBuilder builder = new ConfigurationBuilder();
                _ = builder.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "AppSettings.Movies3Data.json"));
    
                var root = builder.Build();
                AttachedDb = root.GetConnectionString("AttachedDb")!;
            }
            static AppSettingsConfigSingleton() { }
    
            public string? AttachedDb { get; init; }
    
            public static AppSettingsConfigSingleton Instance { get { return Nested.instance; } }
    
            private class Nested
            {
                // Explicit static constructor to tell C# compiler
                // not to mark type as beforefieldinit
                static Nested()
                {
                }
    
                internal static readonly AppSettingsConfigSingleton instance = new();
            }
        }
    

    And it "works well" by also reading JSON content just having been modified by admins at run-time. (Which would be the Entity Framework Core "localdb" location for the unit-of-work pattern in a multi-UI solution). Thanks again to you too, @EldHasp