Note that there are some explanatory texts on larger screens.

plurals
  1. PO.NET custom configuration section: Configuration.GetSection throws 'unable to locate assembly' exception
    primarykey
    data
    text
    <p>I have created a custom configuration section for a plugin DLL that stores the .config XML in a separate (from the main executable application) file.</p> <p>Here's a sample of the custom section class:</p> <pre><code>using System; using System.Configuration; namespace PluginFramework.MyConfiguration { public class MyConfigurationSettings : ConfigurationSection { private Configuration _Config = null; #region ConfigurationProperties /// &lt;summary&gt; /// A custom XML section for an application's configuration file. /// &lt;/summary&gt; [ConfigurationProperty("MyProjects", IsDefaultCollection = true)] public MyProjectConfigurationCollection MyProjects { get { return (MyProjectConfigurationCollection) base["MyProjects"]; } } // ... #endregion /// &lt;summary&gt; /// Private Constructor used by our factory method. /// &lt;/summary&gt; private MyConfigurationSettings () : base () { // Allow this section to be stored in user.app. By default this is forbidden. this.SectionInformation.AllowExeDefinition = ConfigurationAllowExeDefinition.MachineToLocalUser; } // ... #region Static Members /// &lt;summary&gt; /// Gets the current applications &amp;lt;MyConfigurationSettings&amp;gt; section. /// &lt;/summary&gt; /// &lt;param name="ConfigLevel"&gt; /// The &amp;lt;ConfigurationUserLevel&amp;gt; that the config file /// is retrieved from. /// &lt;/param&gt; /// &lt;returns&gt; /// The configuration file's &amp;lt;MyConfigurationSettings&amp;gt; section. /// &lt;/returns&gt; public static MyConfigurationSettings GetSection (ConfigurationUserLevel ConfigLevel) { string appDataPath = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); string localDataPath = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); System.Configuration.ExeConfigurationFileMap exeMap = new ExeConfigurationFileMap(); exeMap.ExeConfigFilename = System.IO.Path.Combine(appDataPath, @"MyCompany\MyPluginApp\Default.config"); exeMap.RoamingUserConfigFilename = System.IO.Path.Combine(appDataPath, @"MyCompany\MyPluginApp\Roaming.config"); exeMap.LocalUserConfigFilename = System.IO.Path.Combine(localDataPath, @"MyCompany\MyPluginApp\Local.config"); System.Configuration.Configuration Config = ConfigurationManager.OpenMappedExeConfiguration(exeMap,ConfigLevel); MyConfigurationSettings myConfigurationSettings = null; try { myConfigurationSettings = (MyConfigurationSettings)Config.GetSection("MyConfigurationSettings"); } catch (System.Exception ex) { // ConfigurationErrorsException caught here ... } if (myConfigurationSettings == null) { myConfigurationSettings = new MyConfigurationSettings(); Config.Sections.Add("MyConfigurationSettings", myConfigurationSettings); } } if(myConfigurationSettings != null) { myConfigurationSettings._Config = Config; } return myConfigurationSettings; } #endregion } } // PluginFramework.MyConfiguration </code></pre> <p>The .config XML generated when saving 1st time looks like this:</p> <pre class="lang-xml prettyprint-override"><code>&lt;?xml version="1.0" encoding="utf-8"?&gt; &lt;configuration&gt; &lt;configSections&gt; &lt;!-- The exception complains about the following line (assembly attributes are compliant): --&gt; &lt;section name="MyConfigurationSettings" type="PluginFramework.MyConfiguration.MyConfigurationSettings, PluginFramework, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" allowDefinition="Everywhere" allowExeDefinition="MachineToLocalUser" /&gt; &lt;/configSections&gt; &lt;MyConfigurationSettings&gt; &lt;!-- Config properties are serialized fine according MyConfigurationSettings properties marked with the ConfigurationProperty attribute ... --&gt; &lt;MyProjects&gt; &lt;MyProjectConfiguration GUID="{4307AC92-8180-4686-9322-830312ED59AB}"&gt; &lt;!-- ... more complex configuration elements --&gt; &lt;/MyProjectConfiguration&gt; &lt;/MyProjects&gt; &lt;/MyConfigurationSettings&gt; &lt;/configuration&gt; </code></pre> <p>When this XML is tried to be loaded using <code>Config.GetSection()</code> on subsequent runs, I catch a <code>ConfigurationErrorsException</code> at the line marked in the XML sample, stating that the assembly <code>MyPlugin</code> or one of it's dependencies couldn't be located (please forgive that I'm not posting the original exception message, but I have it only in german, and doubt this text would be helpful here). The inner exception comes from <code>System.IO</code> while trying to load the assembly and get reflection to resolve the 'MyConfigurationSettings' class type.</p> <p>To precise the situation, the code from above is placed inside a framework DLL (assembly), that in turn is referenced by the actual plugin DLL loaded from the main application.</p> <p>The following UML diagram illustrates the several components' relationships: <img src="https://i.stack.imgur.com/qse1w.png" alt="Main App plugin and framework components"></p> <p>After looking around a bit about this problem, I have the feeling it's necessary to strong name (sign) the assembly exporting the <code>MyConfigurationSettings</code> class (i.e. <code>PluginFramework</code>) and register it with the GAC. I didn't try this yet, and would like to avoid this step for several reasons (before knowing if it could even help and it's the only choice to solve the problem).</p> <p>So here are the questions (sorry I'm placing actually 4 questions here, but they're so strongly related that it wouldn't make sense to create separate SO questions for them).</p> <ol> <li><p>Could I solve the locating failure problem by strong naming the assembly in question and registering it with the GAC?</p></li> <li><p>Stupidly enough the assembly the configuration management complains about, is guaranteed to be loaded (since it calls <code>Configuration.GetSection()</code> itself).<br> Is there may be a way to register the assembly or the appropriate configuration type de-/serializers explicitly with the <code>ConfigurationManager</code> or <code>Confguration</code> class?</p></li> <li><p>I'm also interested in more information about <a href="https://stackoverflow.com/questions/14718262/net-custom-configuration-section-configuration-getsection-throws-unable-to-lo#comment20591740_14718262">Hans Passant's comment</a> mentioning this might be a problem caused by the way the (primary) assembly is loaded from the main app. I have no control over this mechanism, and if this causes this behavior inherently I'd like to know if there's a reasonable workaround?</p></li> <li><p>Another idea (if anything of the above fails to show a way) is to completely manage a configuration XML format natively (using XML de-/serialization support) and from where to load and merge the configuration files. If this is the most appropriate option, can anyone give good pointers how to do this efficiently (least necessary code for managing paths' and merging)?</p></li> </ol> <p><strong>Update:</strong><br> Since no one seems to be able to give more insight about this question(s) (the 2 answers don't really get me further), I'm changing to option from 4., doing it all manually.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. COOne thing I tell you for sure - it not need to be in GAC. First, make sure that your Section Handler lives in the same directory as rest of the code. Second, make sure you use right configuration manager. Third, make sure you have all {<!-- Config properties ... -->} corresponding to properties in your "MyConfigurationSettings" This is to begin... And Fourth! Looking at your class... I don't think you utilizing it right. You need properties there, not "GetSection". This is whole idea that you call GetSection and framework finds you right section handler where you only have to do -call property
      singulars
    2. COIf the main application is strong-named then any assembly it references must also be strong-named.
      singulars
    3. CO@T.S. Sounds promising! Have a look at some edits to improve the question. The mentioned framework DLL is in the same directory as the plugin DLL, but not in the same directory as the main application executable. I think your points about the configuration properties might be irrelevant (at least for this particular exception, it complains exactly about the line I've marked in the .config XML). About utilization of the `GetSection()` method, this one's intended just for convenience for accessing this specific section, I have no idea where or how I could replace this with a property ...
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload