2

First off, let me apologize in advance for the extremely long question -- kudos to anyone that makes it to the end!


I have a C#/.NET 3.5 class library which is not installed in the GAC since the class library is an add-in to another program (ArcMap.exe). The program actually extracts the .dll from an archive on startup to a folder under the user's Local Settings\Application Data folder, but I am able to get its location at runtime using this.GetType().Assembly.Location.

In the library I have a class called CustomConfigSection that is referenced in the .config file.

The library has a class with a method LoadConfigSection() that reads from a .config file (stored in the user's Application Data folder) using ConfigurationManager.OpenMappedExeConfiguration() and returns a CustomConfigSection -- or it should. What happens is GetSection() throws a nasty ConfigurationErrorsException saying it can't find the assembly that contains my CustomConfigSection.

The annoying thing is that this was working two days ago. I think a Windows Update broke this. I have gone back and tried previous versions of my code that I know worked fine, to no avail. Something changed in the environment, not in my code, but whatever it was also happens on other machines now as well, so it's not just me!

Here is an example .config file:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="customConfigSection" type="TestExeConfigurationFileMapAddin.CustomConfigSection, TestExeConfigurationFileMapAddin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    </configSections>
    <customConfigSection>
        <customConfigCollection>
            <customConfig name="asdf" />
            <customConfig name="1234" />
            <customConfig name="jlkjjkljj" />
        </customConfigCollection>
    </customConfigSection>
</configuration>

And the code I am using to read it (which as I mentioned worked perfectly 2 days ago):

    private CustomConfigSection LoadConfigSection()
    {
        ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
        configFileMap.ExeConfigFilename = m_userConfigFilePath;
        Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
        CustomConfigSection configSection = config.GetSection("customConfigSection") as CustomConfigSection;
        return configSection;
    }

m_userConfigFilePath is a valid path to the .config file, and the Configuration object's HasFile property is true.

Here is the error I get, after enabling Fusion assembly binding logging:

System.Configuration.ConfigurationErrorsException: An error occurred creating the configuration section handler for customConfigSection: Could not load file or assembly 'TestExeConfigurationFileMapAddin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified. (C:\Documents and Settings\...\Application Data\TestExeConfigurationFileMapAddin\test.config line 4) ---> System.IO.FileNotFoundException: Could not load file or assembly 'TestExeConfigurationFileMapAddin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
File name: 'TestExeConfigurationFileMapAddin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'
   at System.Configuration.TypeUtil.GetTypeWithReflectionPermission(IInternalConfigHost host, String typeString, Boolean throwOnError)
   at System.Configuration.MgmtConfigurationRecord.CreateSectionFactory(FactoryRecord factoryRecord)
   at System.Configuration.BaseConfigurationRecord.FindAndEnsureFactoryRecord(String configKey, Boolean& isRootDeclaredHere)

Assembly manager loaded from:  C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
Running under executable  C:\Program Files\ArcGIS\Desktop10.0\Bin\ArcMap.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: User = ...
LOG: DisplayName = TestExeConfigurationFileMapAddin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
 (Fully-specified)
LOG: Appbase = file:///C:/Program Files/ArcGIS/Desktop10.0/Bin/
LOG: Initial PrivatePath = NULL
Calling assembly : System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Program Files\ArcGIS\Desktop10.0\Bin\ArcMap.exe.Config
LOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Program Files/ArcGIS/Desktop10.0/Bin/TestExeConfigurationFileMapAddin.DLL.
LOG: Attempting download of new URL file:///C:/Program Files/ArcGIS/Desktop10.0/Bin/TestExeConfigurationFileMapAddin/TestExeConfigurationFileMapAddin.DLL.
LOG: Attempting download of new URL file:///C:/Program Files/ArcGIS/Desktop10.0/Bin/TestExeConfigurationFileMapAddin.EXE.
LOG: Attempting download of new URL file:///C:/Program Files/ArcGIS/Desktop10.0/Bin/TestExeConfigurationFileMapAddin/TestExeConfigurationFileMapAddin.EXE.

   --- End of inner exception stack trace ---
   at System.Configuration.BaseConfigurationRecord.FindAndEnsureFactoryRecord(String configKey, Boolean& isRootDeclaredHere)
   at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
   at System.Configuration.BaseConfigurationRecord.GetSection(String configKey, Boolean getLkg, Boolean checkPermission)
   at System.Configuration.Configuration.GetSection(String sectionName)
   at TestExeConfigurationFileMapAddin.Form1.LoadConfigSection() in C:\CSProjects\TestExeConfigurationFileMapAddin\TestExeConfigurationFileMapAddin\Form1.cs:line 46
   at TestExeConfigurationFileMapAddin.Form1.LoadConfig() in C:\CSProjects\TestExeConfigurationFileMapAddin\TestExeConfigurationFileMapAddin\Form1.cs:line 28

And the Fusion failed binding log itself:

*** Assembly Binder Log Entry  (7/29/2011 @ 12:46:02 PM) ***

The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.

Assembly manager loaded from:  C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
Running under executable  C:\Program Files\ArcGIS\Desktop10.0\Bin\ArcMap.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: User = ...
LOG: DisplayName = TestExeConfigurationFileMapAddin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
 (Fully-specified)
LOG: Appbase = file:///C:/Program Files/ArcGIS/Desktop10.0/Bin/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = NULL
Calling assembly : System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Program Files\ArcGIS\Desktop10.0\Bin\ArcMap.exe.Config
LOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Program Files/ArcGIS/Desktop10.0/Bin/TestExeConfigurationFileMapAddin.DLL.
LOG: Attempting download of new URL file:///C:/Program Files/ArcGIS/Desktop10.0/Bin/TestExeConfigurationFileMapAddin/TestExeConfigurationFileMapAddin.DLL.
LOG: Attempting download of new URL file:///C:/Program Files/ArcGIS/Desktop10.0/Bin/TestExeConfigurationFileMapAddin.EXE.
LOG: Attempting download of new URL file:///C:/Program Files/ArcGIS/Desktop10.0/Bin/TestExeConfigurationFileMapAddin/TestExeConfigurationFileMapAddin.EXE.
LOG: All probing URLs attempted and failed.

Clearly the ConfigurationManager is looking for the assembly containing my CustomConfigSection from the wrong location -- as to why this only started happening recently I have no idea, but I did install a bunch of Windows Updates 2-3 days ago. I am running Windows XP Pro SP3 32-bit.

Without fully understanding what all of these terms mean, the Fusion log gives me hope that I might be able to change the load context or policy to coerce it into loading the assembly from the correct location. Is that true, and if so, how?

blah238
  • 1,796
  • 2
  • 18
  • 51
  • have your windows account permissions changed recently? I know that might sound like a dumb question as the dll is in your documents & settings area, but I recently discovered (Win7) that I wasn't the owner of my documents & settings – tomfumb Jul 30 '11 at 18:52
  • As far as I know, no, I am still an administrator on the machine. – blah238 Jul 30 '11 at 19:53
  • Well I am getting the same thing on a Win7 x64 machine that I know I have full admin rights on, etc. etc. According to [this post](http://www.codeproject.com/KB/dotnet/mysteriesofconfiguration.aspx?msg=3307466#xx3307466xx) by Jon Rista from 2009, this is how it's supposed to work -- due to the security restrictions in .NET, the assembly needs to be in the hosting application's private bin search path. Why it worked previously and no longer is anyone's guess, but if true, I'm guessing a Windows update tightened up that security. Please let me know if you find the same with your add-in. – blah238 Aug 01 '11 at 08:48
  • I am pretty sure the June 2011 .NET Framework security update ([MS11-039](http://www.microsoft.com/technet/security/bulletin/ms11-039.mspx)) was the change that caused this to start happening. Sounds like the vendor (ESRI) needs to update their program to deal with the increased security. Anyways, I have moved on and am now using XML (de)serialization instead of .NET configuration. – blah238 Aug 02 '11 at 07:10

1 Answers1

3

Using Assembly.LoadFrom() and handling the AssemblyResolve event was the key -- the code example in this answer resolved the issue for me. I would love to hear any experts' thoughts on how this works.

Community
  • 1
  • 1
blah238
  • 1,796
  • 2
  • 18
  • 51