I have a class library that is usually called from a .net console or web application. It integrates with various components, and relies on an app.config or web.config.
I
You can always include additional sections within config files. In your ipy.exe.config file you can add an include to import external config settings; say myApp.config.
In a batch/command file you can always copy over a specific .config set into myApp.config and therefore run with different config files on demand.
Have a peek at this blog on how to achieve this; http://weblogs.asp.net/pwilson/archive/2003/04/09/5261.aspx
I attempted to follow the answers above, but found it too complex. If you know exactly what attribute you need from your App.config file, then you can place it directly in the code. For instance, a dll I had imported needed to know the AssemblyPath attribute in my App.Config file.
import clr
import System.Configuration
clr.AddReference("System.Configuration")
from System.Configuration import ConfigurationManager
ConfigurationManager.AppSettings["AssemblyPath"] = 'C:/Program Files (X86)/...
This was all I needed, and the class library I was connecting to was able to see the AssemblyPath attribute it needed to run.
I have a working solution with code sample. See my blog: http://technomosh.blogspot.com/2012/01/using-appconfig-in-ironpython.html
It requires a special proxy class which is injected to the ConfigurationManager.
Here is the source for the ConfigurationProxy library:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Configuration.Internal;
using System.Xml;
using System.Collections.Specialized;
using System.Reflection;
using System.IO;
namespace IronPythonUtilities
{
/// <summary>
/// A custom app.config injector for use with IronPython code that needs configuration files.
/// The code was taken and modified from the great work by Tom E Stephens:
/// http://tomestephens.com/2011/02/making-ironpython-work-overriding-the-configurationmanager/
/// </summary>
public sealed class ConfigurationProxy : IInternalConfigSystem
{
Configuration config;
Dictionary<string, IConfigurationSectionHandler> customSections;
// this is called filename but really it's the path as needed...
// it defaults to checking the directory you're running in.
public ConfigurationProxy(string fileName)
{
customSections = new Dictionary<string, IConfigurationSectionHandler>();
if (!Load(fileName))
throw new ConfigurationErrorsException(string.Format(
"File: {0} could not be found or was not a valid cofiguration file.",
config.FilePath));
}
private bool Load(string file)
{
var map = new ExeConfigurationFileMap { ExeConfigFilename = file };
config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
var xml = new XmlDocument();
using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read))
xml.Load(stream);
//var cfgSections = xml.GetElementsByTagName("configSections");
//if (cfgSections.Count > 0)
//{
// foreach (XmlNode node in cfgSections[0].ChildNodes)
// {
// var type = System.Activator.CreateInstance(
// Type.GetType(node.Attributes["type"].Value))
// as IConfigurationSectionHandler;
// if (type == null) continue;
// customSections.Add(node.Attributes["name"].Value, type);
// }
//}
return config.HasFile;
}
public Configuration Configuration
{
get { return config; }
}
#region IInternalConfigSystem Members
public object GetSection(string configKey)
{
if (configKey == "appSettings")
return BuildAppSettings();
object sect = config.GetSection(configKey);
if (customSections.ContainsKey(configKey) && sect != null)
{
var xml = new XmlDocument();
xml.LoadXml(((ConfigurationSection)sect).SectionInformation.GetRawXml());
// I have no idea what I should normally be passing through in the first
// two params, but I never use them in my confighandlers so I opted not to
// worry about it and just pass through something...
sect = customSections[configKey].Create(config,
config.EvaluationContext,
xml.FirstChild);
}
return sect;
}
public void RefreshConfig(string sectionName)
{
// I suppose this will work. Reload the whole file?
Load(config.FilePath);
}
public bool SupportsUserConfig
{
get { return false; }
}
#endregion
private NameValueCollection BuildAppSettings()
{
var coll = new NameValueCollection();
foreach (var key in config.AppSettings.Settings.AllKeys)
coll.Add(key, config.AppSettings.Settings[key].Value);
return coll;
}
public bool InjectToConfigurationManager()
{
// inject self into ConfigurationManager
var configSystem = typeof(ConfigurationManager).GetField("s_configSystem",
BindingFlags.Static | BindingFlags.NonPublic);
configSystem.SetValue(null, this);
// lame check, but it's something
if (ConfigurationManager.AppSettings.Count == config.AppSettings.Settings.Count)
return true;
return false;
}
}
}
and here is how it can be loaded from Python:
import clr
clr.AddReferenceToFile('ConfigurationProxy.dll')
from IronPythonUtilities import ConfigurationProxy
def override(filename):
proxy = ConfigurationProxy(filename)
return proxy.InjectToConfigurationManager()
Finally, a usage sample:
import configproxy
import sys
if not configproxy.override('blogsample.config'):
print "could not load configuration file"
sys.exit(1)
import clr
clr.AddReference('System.Configuration')
from System.Configuration import *
connstr = ConfigurationManager.ConnectionStrings['TestConnStr']
print "The configuration string is {0}".format(connstr)
You can look at the System.Configuration.ConfigurationManager class. More specifically, OpenMappedExeConfiguration method will allow you to load any .config file of your choice. This will give you a Configuration object which exposes the standard AppSettins, ConnectionStrings, SectionGroups and Sections properties.
This approach requires you to pass the name of the config file to your script as a command line argument or to have a code logic to choose the .config file at run-time.
I know no Python, so I would refrain from attempts to post sample code. :-)
Translating this blog post into Python, this should work:
import clr
import System.AppDomain
System.AppDomain.CurrentDomain.SetData(“APP_CONFIG_FILE”, r”c:\your\app.config”)
For a workaround what I did was fill the AppSettings collection for the ConfigurationManager static class "manually", so I created a PY Script and run an "import" of it on IronPython and the settings then will be available for the class library. However I couldn assing values to the ConnectionStrings collection :(
my script looks like this
import clr
clr.AddReferenceToFileAndPath(r'c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.configuration.dll')
from System.Configuration import *
ConfigurationManager.AppSettings["settingA"] = "setting A value here"
ConfigurationManager.AppSettings["settingB"] = "setting B value here"
It would be nice though to know a way to "load" a custom .config file to the ConfigurationManager class.