I'm supporting an ASP (Application Service Provider) style application for my company. Instead of putting each client's settings into a single config file, I wanted to have the main config file point to each clients configuration. After a bit of digging, I came up with a solution that works. I don't know if it is the best solution but it does work. My main config file now looks like:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="FeedProvider"
type="Sol3.Feed.Provider.FeedProviderConfiguration, Sol3.Feed.Provider"
allowDefinition="MachineToApplication" />
</configSections>
<FeedProvider defaultProvider="FeedProvider01">
<providers>
<add name="FeedProvider01"
type="Sol3.Feed.FeedProvider01, Sol3.Feed"
connectionStringName="ConnString"
description="Client 01 Feed Provider" />
<add name="FeedProvider02"
type="Sol3.Feed.FeedProvider02, Sol3.Feed"
connectionStringName="connString"
description="Client 02 Feed Provider" />
</providers>
</FeedProvider>
<appSettings>
<add key="EnvironmentName" value="dev"/>
<!-- add key="EnvironmentName" value="qa"/ -->
<!-- add key="EnvironmentName" value="uat"/ -->
<!-- add key="EnvironmentName" value="prod"/ -->
<add key="Clients" value="3"/>
<add key="Client 1" value="Client Name 01"/>
<add key="Client 2" value="Client Name 02"/>
<add key="Client 3" value="Client Name 03"/>
</appSettings>
</configuration>
A client config file now looks like:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<clear />
<add name="connString" connectionString="[client connection string]" />
</connectionStrings>
<appSettings>
<add key="WatchPath" value="C:\Feeds\ClientN"/>
<add key="FileName" value="sample.csv"/>
<add key="FileType" value="*.csv;*.txt"/>
<add key="StartTime" value="05:00"/>
<add key="EndTime" value="05:00"/>
<add key="ArchiveDays" value="30"/>
</appSettings>
</configuration>
I have a service that will iterate through the appSettings and setup a file handler for each client. The service creates a new ClientInfo object for each client:
#region Constructor
public Service()
{
_clientInfo = new Dictionary<string, ClientInfo>();
_clientList = new List<string>();
_clientCount = Convert.ToInt32(ConfigurationManager.AppSettings.Get("Clients").ToString());
_environmentName = ConfigurationManager.AppSettings.Get("EnvironmentName").ToString();
for (int i = 0; i < _clientCount; i++)
{
string appKey = String.Format("Client {0}", i+1);
string clientName = ConfigurationManager.AppSettings.Get(appKey).ToString();
ClientInfo thisInfo = new ClientInfo(clientName, _environmentName);
_clientList.Add(clientName);
_clientInfo.Add(clientName, thisInfo);
}
}
#endregion
This is the ClientInfo Class and contains the code to read from another config file:
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using ITMS.Feed;
using System.IO;
using System.Diagnostics;
namespace TestHarness
{
public class ClientInfo
{
#region Declarations
private Dictionary<string, object> _config;
private Handler _handler;
#endregion
#region Constructor
public ClientInfo(string clientName, string environmentName)
{
clientName = clientName.Replace(" ", "_");
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = String.Format("{0}_{1}.config", clientName, environmentName); // relative path names possible
if (!File.Exists(Environment.CurrentDirectory + "\\" + fileMap.ExeConfigFilename))
{
EventLog.WriteEntry("TestHarness.ClientInfo"
, String.Format("{0} was not found!", fileMap.ExeConfigFilename)
, EventLogEntryType.Information);
return;
}
// Open another config file
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
// Get the app settings section...
AppSettingsSection section = (AppSettingsSection)config.GetSection("appSettings");
// Get configuration settings and start file watcher for this client...
_config = new Dictionary<string, object>();
// read/write from it as usual
_config.Add("connString", config.ConnectionStrings.ConnectionStrings[0].ConnectionString);
_config.Add("WatchPath", section.Settings["WatchPath"].Value.ToString());
_config.Add("FileType", section.Settings["FileType"].Value.ToString());
_config.Add("StartTime", Convert.ToDateTime(section.Settings["StartTime"].Value.ToString()));
_config.Add("EndTime", Convert.ToDateTime(section.Settings["EndTime"].Value.ToString()));
_handler = new Handler(_config);
_handler.Start();
}
#endregion
}
}
There is still a lot I can do to this but this is the basics of handling a config file that is not your app or web config. Enjoy.
Cross posted from my blog at http://schema.sol3.net/kbarrows