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条回答
The star\"
2楼-- · 2019-01-23 13:02

Unfortunately, you will need to either have the ImportEPDMAddin assembly residing in the same folder as your executable, residing in the .Net framework folder related to the .Net framework you are using (i.e., C:\Windows\Microsoft.NET\Framework\v2.0.50727), or registered in the Global Assembly Cache.

The only other option is, if you know the path to the assembly that contains the configuration handler's defining class, you can load it without a reference with something like this:

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

Make sure you handle the AssemblyResolve event, as this will throw an exception without it.

查看更多
干净又极端
3楼-- · 2019-01-23 13:06

Had to use the fully qualified type string of my module/plugin assembly, which is in a probing directory, so it could be located. Using EntityFramework as an example...

Incorrect:

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

Correct

type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
查看更多
Root(大扎)
4楼-- · 2019-01-23 13:09

I tried AJ's answer, with rileywhite's supplement but I found that did not work for me.

In my scenario, the custom ConfigurationSection class was already in the currently-executing assembly, and trying to load it causes a stack overflow. I also did not want to put it in GAC even though it did resolve the problem as reported by the OP.

In end, I found this to work well enough for my purpose. Maybe others will find it useful:

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>
}
查看更多
我欲成王,谁敢阻挡
5楼-- · 2019-01-23 13:12

Have you made sure that DLL is loaded first? Perhaps with Assembly.LoadFile("PATH")?

If you can't get the classes in System.Configuration to work properly, you can always fall back on using XmlDocument to manually parse the configuration file. Use XPaths to make getting the data easier. For example (assuming your path variable above):

var document = new XmlDocument();
document.Load(path);
var node = document.SelectSingleNode("configuration/importWorkflows/add[@name='KEY']");
// Do whatever with node
查看更多
Lonely孤独者°
6楼-- · 2019-01-23 13:14

Could you verify that the probing paths are setup correctly in your Host application's config file? It is possible that a needed reference is not being loaded in your current application domain.

Assembly Binding ->Probing

查看更多
▲ chillily
7楼-- · 2019-01-23 13:16

In your main applications config file, add the following (where plugins is the folder for your assembly to load from. You can use multiple paths semi-colon separated.

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

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

查看更多
登录 后发表回答