Custom config section: Could not load file or asse

2019-01-23 12:51发布

I'm having a very hard time trying to access a custom configuration section in my config file.

The config file is being read from a .dll that is loaded as a plug-in. I created the Configuration and necessary code using the Configuration Section Designer VS addin.

The namespace is 'ImportConfiguration'. The ConfigurationSection class is 'ImportWorkflows'. The assembly is ImportEPDMAddin.

The xml:

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

Whenever I try to read in the config, I get the error:

An error occurred creating the configuration section handler for importWorkflows: Could not load file or assembly 'ImportEPDMAddin.dll' or one of its dependencies. The system cannot find the file specified.

The dll will not reside in the same directory as the executable as the software that loads the plugin places the dll and it's dependencies in it's own directory. (I can't control that.)

I edited the code for the singleton instance to the following:

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;

I have also tried using a simple NameValueFileSectionHandler as well, but I get an exception saying that it can't load file or assembly 'System'.

I have read numerous blog posts and articles and it sounds like it is possible to read a config file in for a dll, but I just can't get it to work. Any ideas? Thanks.

标签: c# config
7条回答
欢心
2楼-- · 2019-01-23 13:17

To expand on AJ's excellent answer, here is a custom class to assist with the overhead of registering and removing the global event.

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

I would suggest creating an instance in a using statement, like so:

// you'll need to populate these two variables
var configuration = GetConfiguration();
var assembly = GetAssemblyContainingConfig();

using(new AddinCustomConfigResolveHelper(assembly))
{
    return (MyConfigSection)configuration.GetSection("myConfigSection");
}
查看更多
登录 后发表回答