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:
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";
private static string configurationFile;
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
public ConnectionStringSettingsCollection ConnectionStrings
{
get
{
return config.ConnectionStrings.ConnectionStrings;
}
}
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
public static BasicSettingsManager SettingsFactory()
{
if (Directory.Exists(AppDomain.CurrentDomain.BaseDirectory + @"\bin"))
{
configurationFile = string.Format(@"{0}\bin\{1}",
AppDomain.CurrentDomain.BaseDirectory, ConfigurationFileName);
}
else
{
configurationFile = Path.Combine
(AppDomain.CurrentDomain.BaseDirectory, ConfigurationFileName);
}
if (!File.Exists(configurationFile))
{
throw new FileNotFoundException(configurationFile);
}
return CreateSettingsFactoryInternal();
}
public static BasicSettingsManager SettingsFactory(string fullPathToConfigFile)
{
configurationFile = fullPathToConfigFile;
return CreateSettingsFactoryInternal();
}
internal static BasicSettingsManager CreateSettingsFactoryInternal()
{
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.
Robert Williams has been programming web sites since 1996 and employed as .NET developer since its release in 2002.