Click here to Skip to main content
Click here to Skip to main content
Technical Blog

Tagged as

How to store shared app settings and connection strings with your class library

, 19 Mar 2010 CPOL
Rate this:
Please Sign up or sign in to vote.
When working on enterprise level, multi-tiered .Net applications it is not uncommon to want to create a shared class library, that may be used in multiple related projects. For example, let's suppose you are building a public website, a separate private intranet website used by company staff to mana

When working on enterprise level, multi-tiered .Net applications it is not uncommon to want to create a shared class library, that may be used in multiple related projects. For example, let's suppose you are building a public website, a separate private intranet website used by company staff to manage the public site, and one or more console applications that may run as scheduled tasks related to both sites. You may have an console application that creates and emails reports about sales and other data, and another app that encodes video or audio that is uploaded to your site. Finally, you probably have another project for unit tests.

Since all of these projects will be working with the same database you also have a class library in your solution acting as your datalayer, and perhaps another Core library that contains other shared components. Each of these projects has it's own web.config or app.config file, and you had to copy and paste your connection string, smtp server data, and various other appSettings required by all the projects into every .config file. You may be inspired to add a new .config file to your Core library, and store all of the shared appsettings and connection strings in that one central location. If you then delete all of these settings from the other .config files you'll quickly realize that everything breaks. Even setting the "Copy to Output Directory" property of your Core.config file to "Copy always" doesn't fix this. The reason for this of course is that .Net always looks to the host application for the settings.

The solution is to add some code to your Core project that explicitly loads the Core.config file, reads in the data and makes the results available to all the other projects. That code might look something like this:

namespace Williablog.Core.Configuration
{
    using System;
    using System.Collections.Specialized;
    using System.Configuration;
    using System.IO;
 
    public class BasicSettingsManager
    {
        #region fields
 
        private const string ConfigurationFileName = "Williablog.Core.config";
 
        /// <span class="code-SummaryComment"><summary>
</span>        /// default path to the config file that contains the settings we are using
        /// <span class="code-SummaryComment"></summary>
</span>        private static string configurationFile;
 
        /// <span class="code-SummaryComment"><summary>
</span>        /// Stores an instance of this class, to cut down on I/O: No need to keep re-loading that config file
        /// <span class="code-SummaryComment"></summary>
</span>        /// <span class="code-SummaryComment"><remarks>Cannot use system.web.caching since agents will not have access to this by default, so use static member instead.</remarks>
</span>        private static BasicSettingsManager instance;
 
        private static Configuration config;
 
        #endregion
 
        #region Constructors
 
        private BasicSettingsManager()
        {
            ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
            fileMap.ExeConfigFilename = configurationFile;
            config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
        }
 
        #endregion
 
        #region Properties
 
        /// <span class="code-SummaryComment"><summary>
</span>        /// Returns the ConnectionStrings section
        /// <span class="code-SummaryComment"></summary>
</span>        public ConnectionStringSettingsCollection ConnectionStrings
        {
            get
            {
                return config.ConnectionStrings.ConnectionStrings;
            }
        }
 
        /// <span class="code-SummaryComment"><summary>
</span>        /// Returns the AppSettings Section
        /// <span class="code-SummaryComment"></summary>
</span>        public NameValueCollection AppSettings
        {
            get
            {
                NameValueCollection settings = new NameValueCollection();
                foreach (KeyValueConfigurationElement element in config.AppSettings.Settings)
                {
                    settings.Add(element.Key, element.Value);
                }
 
                return settings;
            }
        }
 
        #endregion
 
        #region static factory methods
 
        /// <span class="code-SummaryComment"><summary>
</span>        /// Public factory method
        /// <span class="code-SummaryComment"></summary>
</span>        /// <span class="code-SummaryComment"><returns></returns>
</span>        public static BasicSettingsManager SettingsFactory()
        {
            // If there is a bin folder, such as in web projects look for the config file there first
            if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @"\bin"))
            {
                configurationFile = string.Format(@"{0}\bin\{1}", AppDomain.CurrentDomain.BaseDirectory, ConfigurationFileName);
            }
            else
            {
                // agents, for example, won't have a bin folder in production
                configurationFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigurationFileName);
            }
 
            // If we still cannot find it, quit now!
            if (!File.Exists(configurationFile))
            {
                throw new FileNotFoundException(configurationFile);
            }
 
            return CreateSettingsFactoryInternal();
        }
 
        /// <span class="code-SummaryComment"><summary>
</span>        /// Overload that allows you to pass in the full path and filename of the config file you want to use.
        /// <span class="code-SummaryComment"></summary>
</span>        /// <span class="code-SummaryComment"><param name="fullPathToConfigFile"></param>
</span>        /// <span class="code-SummaryComment"><returns></returns>
</span>        public static BasicSettingsManager SettingsFactory(string fullPathToConfigFile)
        {
            configurationFile = fullPathToConfigFile;
            return CreateSettingsFactoryInternal();
        }
 
        /// <span class="code-SummaryComment"><summary>internal Factory Method
</span>        /// <span class="code-SummaryComment"></summary>
</span>        /// <span class="code-SummaryComment"><returns>ConfigurationSettings object
</span>        /// <span class="code-SummaryComment"></returns>
</span>        internal static BasicSettingsManager CreateSettingsFactoryInternal()
        {
            // If we havent created an instance yet, do so now
            if (instance == null)
            {
                instance = new BasicSettingsManager();
            }
 
            return instance;
        }
 
        #endregion
    }
}

You can then access the appSettings of Core.Config from any of your projects like so:

Console.WriteLine(Williablog.Core.Configuration.BasicSettingsManager.SettingsFactory().AppSettings["Key"]);

To make this work, you will need to set the "Copy to Output Directory" property of your Core.config file to "Copy always"and add a reference to System.Configuration to each of your projects.

We shall take this a step further next time and expand on this technique to enable your Core project to automatically detect wether it is running on localhost, a development environment, QA, or production, and to return the appropriate connection strings and settings for that environment.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Williarob
Software Developer (Senior) Salem Web Network
United States United States
Robert Williams has been programming web sites since 1996 and employed as .NET developer since its release in 2002.

Comments and Discussions

 
QuestionWouldn't it have been possible to simply use the appSettings File attibute? PinmemberJ.F.6-Nov-12 12:06 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.1411023.1 | Last Updated 19 Mar 2010
Article Copyright 2010 by Williarob
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid