Workaround: Missing ConfigurationManager in .NET Core

The game has changed and configuration moving forward is to be done using json files and the beloved ConfigurationManager.AppSettings is going away. The good news: I have a quick class that will ease you into it.

Maybe, like me, you got all excited about .NET Core and thought you would just snag an existing app and dump it’s code into a .NET Core project to see what would happen. After working through some of the missing packages and modifying a few namespaces to make things work you realize you can no longer use ConfigurationManager to retrieve your AppSettings. Bummer.

I was (clearly) faced with this situation but wanted to focus on the other aspects of porting the app and not the mundane issue of configuration so I created a singleton class to handle reading my now-deprecated app.config. I call it… AppConfig. No, seriously. But feel free to make it your own as I release this code for use in whatever shenanigans you deem it worthwhile for.

First up, it’s a singleton or single-instance object that reads your app.config file from the binary’s folder on instantiation and absorbs the key/value pairs into itself since it derives from Dictionary<string, string>. I chose this as it most closely resembles the functionality of using ConfigurationManager.AppSettings (in my humble opinion).

The code? It looks like this:

using System;
using System.Text.RegularExpressions;
 
 namespace DirtyTricks
 {
     public sealed class AppConfig : System.Collections.Generic.Dictionary<string, string>
     {
         private static AppConfig instance = null;
         private static readonly object padlock = new object();
 
         AppConfig()
         {
             //internalDict = new System.Collections.Generic.Dictionary<string, string>();
             string[] OldAppConfig = System.IO.File.ReadAllLines(@"app.config");
             string keyPattern = "key=(?:[\"'](?<1>[^\"']*)[\"']|(?<1>\\S+))";
             string valuePattern = "value=(?:[\"'](?<1>[^\"']*)[\"']|(?<1>\\S+))";
             Match m;
             for (int i = 0; i < OldAppConfig.Length; i++)
             {
                 string thisString = OldAppConfig[i];
                 if (thisString.Contains("add") && thisString.Contains("key") && thisString.Contains("value"))
                 {
                     // We have a valid config item. Time to extract.
                     m = Regex.Match(thisString, keyPattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
                     string keyName = m.Groups[1].Value;
 
                     m = Regex.Match(thisString, valuePattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
                     string keyValue = m.Groups[1].Value;
 
                     if (this.ContainsKey(keyName))
                     {
                         this[keyName] = keyValue;
                     }
                     else
                     {
                         this.Add(keyName, keyValue);
                     }
                 }
             }
         }
 
         public static AppConfig Instance
         {
             get
             {
                 lock (padlock)
                 {
                     if (instance == null)
                     {
                         instance = new AppConfig();
                     }
                     return instance;
                 }
             }
         }
     }
 }

OK, cool. You have the code now how do you use this thing?

Assuming you already have your app.config file in the project, make sure you set the file properties to “Copy to Output Directory” so it is there for access when we need it at runtime. Failure to do this will result in, you know, it not working since the code expects it to be where the action (execution) is.

Next, instantiate the class and use it! I do this in the beginning and access it as:

string email = DirtyTricks.AppConfig.instance["SecretEmailAddressToSendTo"];

OK, I lied. I don’t really use it like this. But this is a decent example. Remember that all values are going to be strings so expect that as a return type.

So what DOESN’T this do? It doesn’t handle different sections. It doesn’t handle duplicate entries (it just takes the last one it reads as gospel and rolls with it).

That’s it! Hope this helps as a quick-fix as it did for me!

Leave a Reply

Your email address will not be published. Required fields are marked *