Search code examples
c#msbuildtfsbuildmsbuildcommunitytasksbadimageformatexception

Intermittent BadImageFormatException building "plugin" DLL on PC or via TFS build


I have an application where several of the assemblies are built separately from the main application. At run-time they live in a folder outside the main BIN folder and loaded by the main application using Assembly.LoadFrom. In the VS project for these "plugin" assemblies, there are references to physical assemblies built from the main application.

Builds for both the main application and the plugins are made by a TFS build server. The assemblies that are used as references by the "plugin" assembly projects are usually taken from a TFS build of the main application, but occasionally they taken from a build made on my PC.

I work on this application daily, and 99% of plugin builds work fine. Then without any obvious explanation, a plugin assembly will fail to be loaded by the main application with the following error:

System.BadImageFormatException: Could not load file or assembly 'file:///C:\Program Files\MyCompany\MainApp\Plugins\MyApp.Plugins.ABC.XYZ.dll' or one of its dependencies. The module was expected to contain an assembly manifest.
File name: 'file:///C:\Program Files\MyCompany\MainApp\Plugins\MyApp.Plugins.ABC.XYZ.dll'
   at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
   at System.Reflection.RuntimeAssembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boolean forIntrospection, Boolean suppressSecurityChecks, StackCrawlMark& stackMark)
   at System.Reflection.Assembly.LoadFrom(String assemblyFile)

When this happens I do a variety of things to try to resolve it, but I don't have a reliable solution. I try all the following and eventually the issue disappears:

  • run the build again
  • update the assemblies that are used as references by the "plugin" assembly projects with new DLLs built by the build server
  • ditto, but with new DLLs built on my PC
  • reboot the build server
  • install Windows Updates on build server
  • go home and the next day find the issue has gone!

Sometimes, when the plugin build made by the build server displays this problem, a build made on my PC will work. Other times both builds will display the problem.

Up until now the build config for both the main application and plugin solutions has targeted "Any CPU". Today (after seeming lots of S/O posts relating this exception to the processor architecture that is targeted) I tried switching both to target x64, but this has not made any difference.

I don't know what else to look at ... any ideas?


Solution

  • I figured it out myself. It had nothing to do with the build itself, or which processor architecture was being targeted.

    The assemblies were being corrupted during the installation process. I use MSBUILD Community Tasks to zip the plugin assemblies into a ZIP file for distribution. Although the task completed successfully, and the assemblies could be unzipped, manual inspection of the ZIP files that contained plugins that could not be loaded revealed that they had a CRC error.

    The solution was to use ParallelCompression="false" in the ZIP task, e.g.

    <Zip Files="@(PackageAssemblies);@(PackageAssemblyPDBs);@(PackageDocuments);@(PackageOtherFiles)" Flatten="True" WorkingDirectory="$(MSBuildProjectDirectory)" ZipFileName="$(PackageOutputFolder)\$(PackageName)_$(Major).$(Minor).$(Revision)_Install.zip" ParallelCompression="false" />
    

    Found the clue here: https://groups.google.com/forum/#!topic/msbuildtasks/txBNNAWNwYo