Подтвердить что ты не робот

Как использовать IronPython с App.Config?

У меня есть библиотека классов, которая обычно вызывается из консоли .net или веб-приложения. Он интегрируется с различными компонентами и опирается на app.config или web.config.

Если я хочу использовать библиотеку классов из script (т.е. IronPython), как я могу заставить script использовать конфигурационный файл? В идеале я хочу иметь возможность выбирать конфигурационный файл при запуске script или по соглашению (файл конфигурации находится рядом с файлом script).

Я не хочу, если возможно, изменить ipy.exe.config, поскольку это не будет масштабироваться для нескольких конфигураций без наличия нескольких копий IronPython?

Любые альтернативы?

4b9b3361

Ответ 1

У меня есть рабочее решение с образцом кода. Смотрите мой блог: http://technomosh.blogspot.com/2012/01/using-appconfig-in-ironpython.html

Для этого требуется специальный класс прокси, который вводится в ConfigurationManager.

Вот источник для библиотеки ConfigurationProxy:

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 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 something
            if (ConfigurationManager.AppSettings.Count == config.AppSettings.Settings.Count)
                return true;

            return false;
        }
    }
}

и вот как он может быть загружен из Python:

import clr
clr.AddReferenceToFile('ConfigurationProxy.dll')

from IronPythonUtilities import ConfigurationProxy

def override(filename):
    proxy = ConfigurationProxy(filename)
    return proxy.InjectToConfigurationManager()

Наконец, пример использования:

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)

Ответ 2

Вы можете посмотреть класс System.Configuration.ConfigurationManager. Более конкретно, метод OpenMappedExeConfiguration позволит вам загрузить любой файл .config по вашему выбору. Это даст вам Configuration объект, который предоставляет стандартные свойства AppSettins, ConnectionStrings, SectionGroups и Sections.

Этот подход требует, чтобы вы передали имя файла конфигурации в свой script в качестве аргумента командной строки или чтобы логика кода выбирала файл .config во время выполнения.

Я не знаю Python, поэтому я бы воздержался от попыток опубликовать образец кода.: -)

Ответ 3

Перевод этого сообщения в блоге в Python, это должно работать:

import clr
import System.AppDomain
System.AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", r"c:\your\app.config")

Ответ 4

Вы всегда можете включать дополнительные разделы в файлы конфигурации. В файле ipy.exe.config вы можете добавить include для импорта внешних настроек конфигурации; скажем, myApp.config.

В файле партии/команды вы всегда можете скопировать определенный набор .config в myApp.config и, следовательно, работать с разными конфигурационными файлами по требованию.

Загляните в этот блог о том, как это сделать; http://weblogs.asp.net/pwilson/archive/2003/04/09/5261.aspx

Ответ 5

В качестве обходного пути я сделал заполнение коллекции AppSettings для статического класса ConfigurationManager "вручную", поэтому я создал PY Script и запустил "импорт" его на IronPython, и настройки будут доступны для класс библиотеки. Однако я не мог оценить значения в коллекции ConnectionStrings: (

my Script выглядит следующим образом

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"

Было бы неплохо узнать способ загрузки пользовательского файла .config в класс ConfigurationManager.

Ответ 6

Я попытался выполнить приведенные выше ответы, но нашел это слишком сложным. Если вы точно знаете, какой атрибут вам нужен из вашего файла App.config, вы можете поместить его прямо в код. Например, dll, который я импортировал, должен был знать атрибут AssemblyPath в моем файле App.Config.

import clr
import System.Configuration
clr.AddReference("System.Configuration")
from System.Configuration import ConfigurationManager

ConfigurationManager.AppSettings["AssemblyPath"] = 'C:/Program Files (X86)/...

Это все, что мне было нужно, и библиотека классов, к которой я подключалась, смогла увидеть атрибут AssemblyPath, который должен был выполнить.