C#程序中,不管是Dll还是exe程序,都有可能会有app.config的配置文件。
虽然IronPython可以和C#的Dll无缝引用,但是一旦DLL中使用到了app.config,还是会碰到问题的。
比如,创建了一个Dll(编译后,会生成一个TestClassLibrary.dll的类库)

namespace TestClassLibrary
{
    public class TestDll
    {
        public void Outputconfig()
        {
            Console.WriteLine(ConfigurationManager.AppSettings.Get("testkey"));
        }
    }
}

方法Outputconfig会输出配置文件中的testkey节点信息
app.config的内容为

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="testkey" value="localhost" />
  </appSettings>
</configuration>

此时如果简单的对这个Dll进行调用,如下
import clr
clr.AddReference("TestClassLibrary")
from TestClassLibrary import TestDll
t = TestDll()
t.Outputconfig()
运行后,发现没有任何输出。没有出现预期的localhost的值。

这里直接给出解决方法

import clr
clr.AddReference("System.Configuration")
from System.Configuration.Internal import IInternalConfigSystem

class ConfigurationProxy(IInternalConfigSystem):
    def __init__(self, fileName):
        from System import String
        from System.Collections.Generic import Dictionary
        from System.Configuration import IConfigurationSectionHandler, ConfigurationErrorsException
        self.__customSections = Dictionary[String, IConfigurationSectionHandler]()
        loaded = self.Load(fileName)
        if not loaded:
            raise ConfigurationErrorsException(String.Format("File: {0} could not be found or was not a valid cofiguration file.", fileName))

    def Load(self, fileName):
        from System.Configuration import ExeConfigurationFileMap, ConfigurationManager, ConfigurationUserLevel
        exeMap = ExeConfigurationFileMap()
        exeMap.ExeConfigFilename = fileName
        self.__config = ConfigurationManager.OpenMappedExeConfiguration(exeMap, ConfigurationUserLevel.None);
        return self.__config.HasFile;

    def GetSection(self, configKey):
        if configKey == "appSettings":
            return self.__BuildAppSettings()
        return self.__config.GetSection(configKey);

    def __BuildAppSettings(self):
        from System.Collections.Specialized import NameValueCollection
        coll = NameValueCollection()
        for key in self.__config.AppSettings.Settings.AllKeys:
            coll.Add(key, self.__config.AppSettings.Settings[key].Value); 
        return coll

    def RefreshConfig(self, sectionName):
        self.Load(self.__config.FilePath)

    def SupportsUserConfig(self):
        return False

    def InjectToConfigurationManager(self):
        from System.Reflection import BindingFlags
        from System.Configuration import ConfigurationManager
        configSystem = clr.GetClrType(ConfigurationManager).GetField("s_configSystem", BindingFlags.Static | BindingFlags.NonPublic)
        configSystem.SetValue(None, self);

通过上述的类,可以指定特定的app.config来加载

proxy = ConfigurationProxy(r"E:\TestClassLibrary.dll.config")
proxy.InjectToConfigurationManager()
import clr
clr.AddReference("TestClassLibrary")
from TestClassLibrary import TestDll
t = TestDll()
t.Outputconfig()

这样,就可以在控制台中看到输出的localhost值了

上述只是介绍一种简单的场景。实际在使用的过程中,可能是在初始化对象的时候,就需要从配置文件中获取信息。一旦对象初始化失败,待测方法就无法被正确的调用。
解决方法和上述一样。

参考:
http://www.software-architects.com/devblog/2012/10/29/appconfig-in-IronPython-without-additional-assemblies


agentwx
354 声望23 粉丝

引用和评论

0 条评论