2009-11-05 89 views
20

我很难尝试访问我的配置文件中的自定义配置节。自定义配置节:无法加载文件或程序集

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

命名空间是'ImportConfiguration'。 ConfigurationSection类是'ImportWorkflows'。该程序集是ImportEPDMAddin。

的XML:

<configSections> 
    <section name="importWorkflows" type="ImportConfiguration.ImportWorkflows, ImportEPDMAddin"/> 
    </configSections> 

每当我试着在配置读,我得到的错误:

出错创建importWorkflows配置节处理程序:无法加载文件或程序集“导入EPDMAddin.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以及也试过,但我得到一个异常说它无法加载文件或程序集“系统”。

我已经阅读了许多博客文章和文章,听起来像是可以读取一个dll的配置文件,但我无法让它工作。有任何想法吗?谢谢。

+0

你复制'ImportEPDMAddin.dll.config'到相同的位置吗? – ephemient 2009-11-05 18:49:44

+0

配置是肯定的,因为我已经尝试从另一个类使用DictionarySectionHandler,并且工作。 – ehcanadian 2009-11-05 19:14:32

回答

34

不幸的是,你要么需要有ImportEPDMAddin组装居住在同一文件夹中可执行文件,驻留在关系到你使用(即C .NET Framework中的Net框架文件夹: \ Windows \ Microsoft.NET \ Framework \ v2.0.50727),或者在全局程序集缓存中注册。

唯一的其他选择,如果你知道的路径包含配置处理器的定义类的组件,你可以加载它没有像这样的东西的引用:

//Class global 
private Assembly configurationDefiningAssembly; 

protected TConfig GetCustomConfig<TConfig>(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事件,因为这会在没有它的情况下抛出异常。

+0

非常非常感谢。这工作100%!! – ehcanadian 2009-11-05 20:21:00

+0

这就像一个魅力,用于访问和投射T4文件中的自定义部分的类型。谢谢! – Matt 2014-10-22 21:14:12

+0

@AJ。对不起,你能解释我什么是'configDefiningAssemblyPath' ..它是.exe文件吗? – Ciccio 2014-11-20 16:14:46

0

您是否确定首先加载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 
+0

此方法有效,但我希望坚持配置类。如果一切都失败了,我将不得不接受你的建议。 – ehcanadian 2009-11-05 19:15:38

1

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

Assembly Binding ->Probing

5

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

<runtime> 
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
     <probing privatePath=".;.\Plugins"/> 
    </assemblyBinding> 
</runtime> 

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

+1

请注意,只有在privatePath属性中指定的plugins文件夹是应用程序根目录的子目录时,才能使用探测来解决OP的问题。参见[msdn文档](http://msdn.microsoft.com/en-us/library/15hyw9x3(v = vs.110).aspx) – BitMask777 2015-01-06 19:13:46

4
采取

为了扩大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"); 
} 
0

我试图AJ的答案,与rileywhite的补充,但我发现,并没有为我工作。

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

最后,我发现这个功能对我的目的来说已经足够了。也许别人会发现它有用:

public class CustomConfigurationSection : ConfigurationSection { 
    public CustomConfigurationSection() 
    { 
    var reader = XmlReader.Create(<path to my dll.config>); 
    reader.ReadToDescendant("CustomConfigurationSection"); 
    base.DeserializeElement(reader,false); 
    } 

    // <rest of code> 
} 
0

不得不用我的模块/插件组装,这是在探测目录的完全合格的字符串类型,因此它可以被找到。使用的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" 
相关问题