自定义配置部分:无法加载文件或程序集

我在配置文件中尝试访问自定义配置部分非常困难。

正在从作为插件加载的.dll读取配置文件。 我使用Configuration Section Designer VS addin创建了配置和必要的代码。

命名空间是’ImportConfiguration’。 ConfigurationSection类是“ImportWorkflows”。 程序集是ImportEPDMAddin。

xml:

 

每当我尝试读取配置时,我都会收到错误:

为importWorkflow创建配置节处理程序时出错:无法加载文件或程序集“ImportEPDMAddin.dll”或其依赖项之一。 该系统找不到指定的文件。

dll不会与可执行文件驻留在同一目录中,因为加载插件的软件将dll和它的依赖项放在它自己的目录中。 (我无法控制它。)

我将单例实例的代码编辑为以下内容:

 string path = System.Reflection.Assembly.GetCallingAssembly().CodeBase; path = path.Replace("file:///", ""); System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenExeConfiguration(path); return configuration.GetSection(ImportWorkflowsSectionName) as ImportConfiguration.ImportWorkflows; 

我也尝试过使用一个简单的NameValueFileSectionHandler,但我得到一个例外,说它无法加载文件或程序集’System’。

我已经阅读了大量的博客文章和文章,听起来有可能为dll读取配置文件,但我无法让它工作。 有任何想法吗? 谢谢。

不幸的是,您需要将ImportEPDMAddin程序集与可执行文件驻留在同一文件夹中,驻留在与您正在使用的.Net框架相关的.Net框架文件夹中(即C:\ Windows \ Microsoft.NET \ Framework \ v2.0.50727),或在全局程序集缓存中注册。

唯一的另一个选择是,如果你知道包含配置处理程序的定义类的程序集的路径,你可以在没有引用的情况下加载它,如下所示:

 //Class global private Assembly configurationDefiningAssembly; protected TConfig GetCustomConfig(string configDefiningAssemblyPath, string configFilePath, string sectionName) where TConfig : ConfigurationSection { AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ConfigResolveEventHandler); configurationDefiningAssembly = Assembly.LoadFrom(configDefiningAssemblyPath); var exeFileMap = new ExeConfigurationFileMap(); exeFileMap.ExeConfigFilename = configFilePath; var customConfig = ConfigurationManager.OpenMappedExeConfiguration(exeFileMap, ConfigurationUserLevel.None); var returnConfig = customConfig.GetSection(sectionName) as TConfig; AppDomain.CurrentDomain.AssemblyResolve -= ConfigResolveEventHandler; return returnConfig; } protected Assembly ConfigResolveEventHandler(object sender, ResolveEventArgs args) { return configurationDefiningAssembly; } 

确保你处理AssemblyResolve事件,因为这将抛出一个没有它的exception。

在主应用程序配置文件中,添加以下内容(其中插件是要从中加载程序集的文件夹。您可以使用分号分隔的多个路径。

      

摘自http://msdn.microsoft.com/en-us/library/823z9h8w%28v=vs.90%29.aspx

为了扩展AJ的优秀答案,这里有一个自定义类来协助注册和删除全局事件的开销。

 public sealed class AddinCustomConfigResolveHelper : IDisposable { public AddinCustomConfigResolveHelper( Assembly addinAssemblyContainingConfigSectionDefinition) { Contract.Assert(addinAssemblyContainingConfigSectionDefinition != null); this.AddinAssemblyContainingConfigSectionDefinition = addinAssemblyContainingConfigSectionDefinition; AppDomain.CurrentDomain.AssemblyResolve += this.ConfigResolveEventHandler; } ~AddinCustomConfigResolveHelper() { this.Dispose(false); } public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool isDisposing) { AppDomain.CurrentDomain.AssemblyResolve -= this.ConfigResolveEventHandler; } private Assembly AddinAssemblyContainingConfigSectionDefinition { get; set; } private Assembly ConfigResolveEventHandler(object sender, ResolveEventArgs args) { // often the name provided is partial...this will match full or partial naming if (this.AddinAssemblyContainingConfigSectionDefinition.FullName.Contains(args.Name)) { return this.AddinAssemblyContainingConfigSectionDefinition; } return null; } } 

我建议在using语句中创建一个实例,如下所示:

 // you'll need to populate these two variables var configuration = GetConfiguration(); var assembly = GetAssemblyContainingConfig(); using(new AddinCustomConfigResolveHelper(assembly)) { return (MyConfigSection)configuration.GetSection("myConfigSection"); } 

你能validation在主机应用程序的配置文件中是否正确设置了探测路径吗? 您当前的应用程序域中可能未加载所需的引用。

assembly绑定 – >探测

你确定首先加载了DLL吗? 也许使用Assembly.LoadFile("PATH")

如果无法使System.Configuration中的类正常工作,则可以始终使用XmlDocument手动解析配置文件。 使用XPath可以更轻松地获取数据。 例如(假设您的路径变量在上面):

 var document = new XmlDocument(); document.Load(path); var node = document.SelectSingleNode("configuration/importWorkflows/add[@name='KEY']"); // Do whatever with node 

我尝试了AJ的答案,有赖利白的补充,但我发现这对我不起作用。

在我的方案中,自定义ConfigurationSection类已经在当前正在执行的程序集中,并且尝试加载它会导致堆栈溢出。 我也不想把它放在GAC中,即使它确实解决了OP报告的问题。

最后,我发现这对我的目的来说足够好。 也许其他人会发现它很有用:

 public class CustomConfigurationSection : ConfigurationSection { public CustomConfigurationSection() { var reader = XmlReader.Create(); reader.ReadToDescendant("CustomConfigurationSection"); base.DeserializeElement(reader,false); } //  } 

不得不使用我的模块/插件程序集的完全限定类型字符串,它位于探测目录中,因此可以找到它。 以EntityFramework为例……

不正确:

 type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework" 

正确

 type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"