3

We have an Asp.Net MVC project that we have recently upgraded from .Net 4.6.1 to .Net 4.8. It has some dependencies on other projects in our solution that have also been upgraded. The MVC project itself uses System.IO.Compression to zip some files as does one of the other projects it depends on.

Since upgrading, we are seeing some strange behaviour with System.IO.Compression. If we build the new solution, it doesn't automatically copy System.IO.Compression.dll and System.IO.Compression.FileSystem.dll to the output bin folder. This causes a runtime exception on the lines of code that tries to do zipping…

System.IO.FileNotFoundException: 'Could not load file or assembly 'System.IO.Compression, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or one of its dependencies. The system cannot find the file specified.'

This is unsurprising I suppose if the dll is not even copied to the bin folder.

If I set the "Copy Local" property to true on the System.IO.Compression.dll and System.IO.Compression.FileSystem.dll in the references of the MVC project, the files are copied from

"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.8" to the bin folder, but the following error is shown in the browser when the application first starts…

[BadImageFormatException: Cannot load a reference assembly for execution.]

[BadImageFormatException: Could not load file or assembly 'System.IO.Compression' or one of its dependencies. Reference assemblies should not be loaded for execution.  They can only be loaded in the Reflection-only loader context. (Exception from HRESULT: 0x80131058)]
   System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) +0
   System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) +232
   System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection) +113
   System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +23
   System.Reflection.Assembly.Load(String assemblyString) +35
   System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +48

[ConfigurationErrorsException: Could not load file or assembly 'System.IO.Compression' or one of its dependencies. Reference assemblies should not be loaded for execution.  They can only be loaded in the Reflection-only loader context. (Exception from HRESULT: 0x80131058)]
   System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +767
   System.Web.Configuration.CompilationSection.LoadAllAssembliesFromAppDomainBinDirectory() +256
   System.Web.Configuration.CompilationSection.LoadAssembly(AssemblyInfo ai) +58
   System.Web.Compilation.BuildManager.GetReferencedAssemblies(CompilationSection compConfig) +287
   System.Web.Compilation.BuildManager.GetPreStartInitMethodsFromReferencedAssemblies() +69
   System.Web.Compilation.BuildManager.CallPreStartInitMethods(String preStartInitListPath, Boolean& isRefAssemblyLoaded) +137
   System.Web.Compilation.BuildManager.ExecutePreAppStart() +172
   System.Web.Hosting.HostingEnvironment.Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel, Exception appDomainCreationException) +854

[HttpException (0x80004005): Could not load file or assembly 'System.IO.Compression' or one of its dependencies. Reference assemblies should not be loaded for execution.  They can only be loaded in the Reflection-only loader context. (Exception from HRESULT: 0x80131058)]
   System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +532
   System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +111
   System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +724

Curiously, the previous .Net 4.6.1 version that worked, which had Nuget references to System.IO.Compression, copied the files from

"C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Microsoft\Microsoft.NET.Build.Extensions\net461\lib" into the bin folder. If we manually copy these versions of the files into our .Net 4.8 bin folder, the application works without any exceptions.

I have tried various combinations of bindingRedirects in the web.config file, but without success.

I have been reading other StackOverflow questions that seem related, but haven't been able to a) fully understand the issue and b) know how to fix it so that we can successfully run the .Net 4.8 version and zip files.

Any help would be greatly appreciated

Simon Williams
  • 1,016
  • 3
  • 11
  • 27
  • 2
    Don't copy paste the older binaries from the 4.6 to 4.8. Try running nuget restore again. If it doesn't help, try removing the nuget package and add again in the 4.8 project. – Sathish Guru V Aug 03 '22 at 11:27
  • Thanks for your reply @SathishGuruV. When I restore Nuget packages it says. "All packages are already installed and there is nothing to restore". I have also cleared the Nuget cache and then restored, but the assemblies still do not get copied to the bin folder, causing the runtime error when zipping. – Simon Williams Aug 03 '22 at 12:02
  • 2
    I don't think you need a NuGet package, it should be part of the .NET standard libraries – Charlieface Aug 03 '22 at 12:44
  • I have tried removing all the Nuget references and just referencing the assembly, but it still doesn't copy the dll to the bin folder – Simon Williams Aug 03 '22 at 13:10
  • 2
    You don't need to copy it. Just change the reference to `System.IO.Compression.FileSystem` from the standard Framework libraries, there is no need to `Copy Local` – Charlieface Aug 03 '22 at 13:23
  • Thanks for your reply @Charlieface. I am referencing System IO.Compression.FileSystem and have Copy Local set to false, but I get the same error when zipping - System.IO.FileNotFoundException: 'Could not load file or assembly 'System.IO.Compression, Version=4.2.0.0, – Simon Williams Aug 03 '22 at 13:33
  • 2
    Remove `System.IO.Compression` from references, and re-add it from the standard list of libraries. 4.2.0.0 is the wrong version. – Charlieface Aug 03 '22 at 13:36
  • 1
    Thanks @Charlieface. It is now working. I did what you said, but I also noticed that there were two dependentAssembly entries in the web.Config file for System.IO.Compression both with binding redirects (I had only noticed one previously). I have now removed these completely from web.Config. – Simon Williams Aug 03 '22 at 14:01

1 Answers1

7

@Charlieface has correctly identified that with .Net 4.8 there is no need to reference any Nuget packages in order to use System.IO.Compression and System.IO.Compression.FileSystem to zip files. To make this work, I uninstalled all Nuget references in the solution for System.IO.Compression and System.IO.Compression.ZipFile. Once the Nuget references had been uninstalled, I ensured that the relevant projects had direct Assembly references to System.IO.Compression and System.IO.Compression.FileSystem (i.e. right-click "Add Reference…" or "Add Assembly Reference…")

I also had to remove any entries for System.IO.Compression.* files from app.confg and web.config files. These app.config and web.config entries had bindingRedirects on that were also causing the issue.

Simon Williams
  • 1,016
  • 3
  • 11
  • 27