Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use IronPython with App.Config?

Tags:

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.

If I want to utilise the class library from script (i.e. IronPython), how can I get the script to utilise the config file? Ideally I want to be able to choose the config file when I run the script, or by convention (config file sitting alongside the script file).

I don't want to change the ipy.exe.config if possible as this wouldn't scale for multiple configurations without having multiple copies of IronPython?

Any alternatives?

like image 601
Andrew Rimmer Avatar asked Feb 15 '09 11:02

Andrew Rimmer


People also ask

Does .NET core have app config?

Application configuration in ASP.NET Core is performed using one or more configuration providers. Configuration providers read configuration data from key-value pairs using a variety of configuration sources: Settings files, such as appsettings. json.

What does app config do in C#?

By adding an application configuration file (app. config file) to a C# project, you can customize how the common language runtime locates and loads assembly files. For more information about application configuration files, see How the runtime locates assemblies (. NET Framework).

How do I find app config in Visual Studio?

In Solution Explorer, right-click the project node, and then select Add > New Item. The Add New Item dialog box appears. Expand Installed > Visual C# Items. In the middle pane, select the Application Configuration File template.


1 Answers

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)
like image 89
Moshe Avatar answered Sep 24 '22 21:09

Moshe