Hi Peter,
I have to admit that I belong to the school of thought that says config's
should generally be more closely aligned to the calling exe's - however I
recently had to build a system that supported the use of plug-in's (for
loose-coupling purposes) that could be dropped into a folder and be
immediately available for use by the rest of the system. These plug-ins were
contained in assemblies and so using config files that travelled with the
assembly was what I opted for.
I also use .NET v2.0 and also did find some v1.1 code on the web that
roughly did what I wanted, although I remember having to make a few changes
to it to get it to work (the changes I made were minimal) - like you, I can't
remember the name of the author though (who really ought to get credit for
the code)... Just in case this wasn't the same code you have, I'll quickly
cover the usage scenario...
To use it, you need to:
(a) name the config file the same as the assembly, but with ".config"
appended to the end ofthe name - so e.g., if your assembly is called
"Hello.World.dll" then the config should be named "Hello.World.dll.config"
(b) make sure the config is in the same folder as the assembly
(c) have your config look something like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="assemblySettings"
type="System.Configuration.DictionarySectionHandle r" />
<section name="otherAssemblySettings"
type="System.Configuration.DictionarySectionHandle r" />
</configSections>
<assemblySettings>
<add key="SomeParam1" value="SomeValue1"/>
<add key="SomeParam2" value="SomeValue2"/>
<add key="SomeParam3" value="SomeValue3"/>
</assemblySettings>
<otherAssemblySettings>
<add key="SomeOtherParam1" value="SomeOtherValue1"/>
<add key="SomeOtherParam2" value="SomeOtherValue2"/>
<add key="SomeOtherParam3" value="SomeOtherValue3"/>
</otherAssemblySettings>
</configuration>
(d) from your code, you can get the two separate config sections doing
something like (not compiled/tested):
AssemblyConfig m_assemblyConfig = new
AssemblyConfig(Assembly.GetCallingAssembly());
AssemblyConfig m_otherConfig = new
AssemblyConfig(Assembly.GetCallingAssembly(), @"otherAssemblySettings");
string someSetting = m_assemblyConfig[@"SomeParam1"];
string someOtherSetting = m_otherConfig[@"SomeOtherParam1"];
Here's what the main code looks like (again not compiled/tested):
using System;
using System.Reflection;
using System.Collections;
using System.Xml;
using System.Configuration;
using System.Runtime.CompilerServices;
namespace Put.Your.Namespace.Here
{
public class AssemblyConfig
{
[MethodImpl(MethodImplOptions.NoInlining)]
public AssemblyConfig() : this(Assembly.GetCallingAssembly())
{
}
public AssemblyConfig(Assembly assembly)
{
m_settings = GetConfig(assembly);
}
public AssemblyConfig(string nodeName)
{
m_settings = GetConfig(Assembly.GetCallingAssembly(), nodeName);
}
public AssemblyConfig(Assembly assembly, string nodeName)
{
m_settings = GetConfig(assembly, nodeName);
}
public string this[string key]
{
get
{
string settingValue = null;
if (m_settings != null)
{
settingValue = m_settings[key] as string;
}
return (settingValue == null ? "" : settingValue);
}
}
public IDictionary Settings
{
get { return m_settings; }
}
protected IDictionary m_settings;
public static IDictionary GetConfig()
{
return GetConfig(Assembly.GetCallingAssembly());
}
public static IDictionary GetConfig(Assembly assembly)
{
return GetConfig(assembly, @"assemblySettings");
}
public static IDictionary GetConfig(Assembly assembly, string
nodeName)
{
IDictionary dictionary = null;
string configFile = assembly.CodeBase + @".config";
XmlDocument configDocument = new XmlDocument();
configDocument.Load(new XmlTextReader(configFile));
XmlNodeList nodes = configDocument.GetElementsByTagName(nodeName);
foreach (XmlNode node in nodes)
{
if (node.LocalName == nodeName)
{
DictionarySectionHandler sectionHandler = new
DictionarySectionHandler();
dictionary = (IDictionary)sectionHandler.Create(null,
null, node);
break;
}
}
return dictionary;
}
}
}
One last thing to mention - I have definitely got this working in .NET v2.0
with no probs, however this was in a non-GAC scenario (the plug-ins that used
this code were not hosted in the GAC) - if tihs code doesn't work in your
setup, then it may well have something to do with OS/.Net
permissioning/security and/or the fact that your assemblies are being hosted
inside of the GAC (i'm too tired to think why this late in the day :-))..
Hope this helps you out...
Kind regards,
Patrick
--
Patrick Simpe-Asante
MCAD, MSCD.Net
"Peter Bradley" wrote:
OK. A bit behind the times, I know; but we're just moving over to .NET 2.0.
How on earth do you manage configuration settings in a class library in .NET
2.0? In version 1.1, we used a handy class called AssemblySettings that
someone (I forget his name) had written. When the class library was
finished, you deployed it to the GAC and put the configuration files in the
GAC with the class library assembly. This no longer works. In fact trying
to get configuration data from anywhere but the calling executable falls
over.
This can't be correct. Our n-Tier architecture uses class libraries to
access data from the database and needs to obtain a connection string from a
configuration file. It's no good putting the configuration in the calling
executable because the calling executable does not know anything about the
database, and anyway the whole point of a class library is that it can be
called by many other objects. We don't want the same configuration data
spread all over the place.
Surely there's a way to fix this. Does anyone know how?
Peter (spitting blood and calling Microsoft all sorts of things you don't
want to hear)