Click here to Skip to main content
15,885,985 members
Articles / All Topics

How to Store Shared App Settings and Connection Strings with Your Class Library

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
19 Mar 2010CPOL2 min read 12K   1   1
This post will show you how to store shared app settings and connection strings with your class library

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 a 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 its 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:

C#
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";
 
        /// <summary>
        /// default path to the config file that contains the settings we are using
        /// </summary>
        private static string configurationFile;
 
        /// <summary>
        /// Stores an instance of this class, to cut down on I/O: 
        /// No need to keep re-loading that config file
        /// </summary>
        /// <remarks>Cannot use system.web.caching since agents will not 
        /// have access to this by default, so use static member instead.</remarks>
        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
 
        /// <summary>
        /// Returns the ConnectionStrings section
        /// </summary>
        public ConnectionStringSettingsCollection ConnectionStrings
        {
            get
            {
                return config.ConnectionStrings.ConnectionStrings;
            }
        }
 
        /// <summary>
        /// Returns the AppSettings Section
        /// </summary>
        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
 
        /// <summary>
        /// Public factory method
        /// </summary>
        /// <returns></returns>
        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();
        }
 
        /// <summary>
        /// Overload that allows you to pass in the full path and 
        /// filename of the config file you want to use.
        /// </summary>
        /// <param name="fullPathToConfigFile"></param>
        /// <returns></returns>
        public static BasicSettingsManager SettingsFactory(string fullPathToConfigFile)
        {
            configurationFile = fullPathToConfigFile;
            return CreateSettingsFactoryInternal();
        }
 
        /// <summary>internal Factory Method
        /// </summary>
        /// <returns>ConfigurationSettings object
        /// </returns>
        internal static BasicSettingsManager CreateSettingsFactoryInternal()
        {
            // If we haven't 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:

C#
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)


Written By
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? Pin
J.F.6-Nov-12 11:06
J.F.6-Nov-12 11:06 

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

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