1
\$\begingroup\$

I inherited a solution with many projects, and one of them contains hard coded database connection parameters. These are referenced in a number of other projects, and many of those are dependencies of the entry assembly. The solution has multiple entry assemblies or deployment units, intended as microservices.

My first goal is to remove the hard coded db username/password, but I can't restructure the solution dramatically, or create multiple solutions within the git repo. I'm thinking of creating a new project within the solution that returns app settings of the entry assembly, at which point the db params can be placed in the app config files for each of the web projects, and removed from hard coded struct where they are currently defined.

using System.Collections.Specialized;
using System.Reflection;

namespace DMConfiguration
{
    public static class ConfigurationManager
    {
        private static NameValueCollection _settings;
        private static readonly object LOCK = new object();

        /// <summary>
        /// Gets the AppSettings from the entry assembly
        /// </summary>
        public static NameValueCollection AppSettings 
        { 
            get {
                if (_settings == null)
                {
                    lock (LOCK)
                    {
                        if (_settings == null)
                        {
                            var appSettings = new NameValueCollection();

                            var config = System.Configuration.ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location);

                            foreach (var key in config.AppSettings.Settings.AllKeys)
                            {
                                var kv = config.AppSettings.Settings[key];

                                appSettings.Add(key, kv.Value);
                            }

                            _settings = appSettings;
                        }
                    }
                }

                return _settings;
            }
        }
    }
}

I ran this in a small throwaway solution to see if it produced the desired results, and it does. For example, from my main console project, I call into ClassLibrary2:

using DMConfiguration;
using System;

namespace ClassLibrary2
{
    public class ClassTwo
    {
        public void Talk()
        {
            // notice familiar interface for accessing app settings
            var myValue = ConfigurationManager.AppSettings["MyKey"];

            Console.WriteLine("ClassLibrary2 says " + myValue);
        }

    }
}

However, despite some searching, I have not found any information regarding the wisdom of this approach. Before I commit to it, I'd appreciate any feedback about potential problems that might come up.

\$\endgroup\$
6
  • \$\begingroup\$ does the original project works with multiple databases or just one database ? is it possible to create a library class within the solution to be used as Data Access Layer? \$\endgroup\$
    – iSR5
    Aug 10, 2022 at 17:36
  • \$\begingroup\$ @iSR5, it's a single database, and there is an intended data access layer, but there are multiple projects reaching in for the hard coded constants. I just reviewed the call hierarchy, and it looks like 5 of 10 web projects will ultimately depend on them. I'm thinking I can add those values to the app.config of each of those projects, and use something like what I posted. \$\endgroup\$
    – Tap
    Aug 10, 2022 at 17:44
  • \$\begingroup\$ I should add that the entire codebase is atrocious, as you can probably guess since they hard coded something like that. \$\endgroup\$
    – Tap
    Aug 10, 2022 at 17:52
  • 2
    \$\begingroup\$ then I guess your approach is feasible, however, you should avoid class names that are already used in .NET, such as ConfigurationManager to avoid confusion. you can use a prefix to distinguish them. \$\endgroup\$
    – iSR5
    Aug 10, 2022 at 17:58
  • \$\begingroup\$ Thank you @iSR5 for taking a look. I appreciate the advice. \$\endgroup\$
    – Tap
    Aug 10, 2022 at 18:05

1 Answer 1

1
\$\begingroup\$

Maybe i have missunderstood something, but it's not clear to me why not simply access the right file AppSetting as you already do, thought ConfigurationManager class and providing the right path.

If for simplicity you would "cache" the result, i would sugget a stati class with a static constructor that will store result in a property (should be thread safe and CofigurationManager definly is).

I mean something as follow :

public static class CMWrapper
{
    public static AppSettingsSection AppSettings { get; private set; }

    static CMWrapper ()
    {
        if ( CMWrapper.AppSettings == null )
            CMWrapper.AppSettings = ConfigurationManager.OpenExeConfiguration(Assembly.GetEntryAssembly().Location).AppSettings;
    }
}
\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.