【问题标题】:Custom config section: Could not load file or assembly自定义配置部分:无法加载文件或程序集
【发布时间】:2010-12-13 13:14:41
【问题描述】:

我很难访问配置文件中的自定义配置部分。

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

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

xml:

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

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

为 importWorkflows 创建配置节处理程序时出错:无法加载文件或程序集“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,但我收到一个异常,说它无法加载文件或程序集“系统”。

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

【问题讨论】:

  • 您是否也将ImportEPDMAddin.dll.config 复制到同一位置?
  • 配置肯定在那里,因为我尝试使用另一个类的 DictionarySectionHandler 并且有效。

标签: c# config


【解决方案1】:

不幸的是,您需要将ImportEPDMAddin 程序集与您的可执行文件放在同一文件夹中,该程序集位于与您正在使用的 .Net 框架相关的 .Net 框架文件夹中(即 C:\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 事件,因为没有它会引发异常。

【讨论】:

  • 这就像在 T4 文件中访问和转换自定义部分的类型的魅力。谢谢!
  • @AJ。对不起,你能解释一下configDefiningAssemblyPath..是什么。是.exe文件吗?
  • 在单元测试情况下使用它是一种享受。谢谢
【解决方案2】:

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

<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

【讨论】:

  • 请注意,只有当 privatePath 属性中指定的 plugins 文件夹是应用程序根目录的子目录时,使用探测来解决 OP 的问题才有效。见msdn docs
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • 此方法有效,但我希望坚持使用配置类。如果一切都失败了,我将不得不接受你的建议。
    【解决方案5】:

    您能否验证您的主机应用程序的配置文件中是否正确设置了探测路径?您当前的应用程序域中可能没有加载所需的引用。

    Assembly Binding ->Probing

    【讨论】:

      【解决方案6】:

      必须使用我的模块/插件程序集的完全限定类型字符串,它位于探测目录中,因此可以找到它。以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"
      

      【讨论】:

        【解决方案7】:

        我尝试了 AJ 的答案,以及 rileywhite 的补充,但我发现这对我不起作用。

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

        最后,我发现这足以满足我的目的。也许其他人会觉得它有用:

        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>
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-09-26
          • 2016-07-19
          • 2015-05-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多