Runtime: System.IO.Compression.ZipFile assembly empty for net46

Created on 23 Dec 2016  路  12Comments  路  Source: dotnet/runtime

The System.IO.Compression.ZipFile assembly does not contain any public classes for net46. I expected the package to at least, well, contain the ZipFile class.

Background:
Because of issues like dotnet/sdk#514, I've enabled DisableImplicitFrameworkReferences in my project when building for net46 and I'm not referencing the NetFX versions of System.IO.Compression and friends.

But it appears that in this configuration the ZipFile class is not available.

Verified on both the public 4.3.0 NuGet package as well as the 4.4.0-beta-24823-02 package from MyGet

area-Infrastructure-libraries tracking-external-issue

Most helpful comment

Consider this scenario:

C:\Users\frede\Source\Repos\repro>dotnet --version
1.0.0-preview5-004232

with repro.csproj:

<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net461</TargetFramework>
    <RuntimeIdentifier>win7-x64</RuntimeIdentifier>
  </PropertyGroup>

  <ItemGroup>
    <Compile Include="**\*.cs" />
    <EmbeddedResource Include="**\*.resx" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="NETStandard.Library" Version="1.6.1" />
  </ItemGroup>

</Project>

and Program.cs:

using System;
using System.IO.Compression;

class Program
{
    static void Main(string[] args)
    {
        ZipFile.CreateFromDirectory("bin\\", "test.zip");
    }
}

Then:

dotnet restore
dotnet build

creates the following warning (which turns into an error in certain cases):

C:\Program Files\dotnet\sdk\1.0.0-preview5-004232\Microsoft.Common.CurrentVersion.targets(1909,5): warning MSB3243: No way to resolve conflict between "System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" and "System.IO.Compression, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089". Choosing "System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" arbitrarily. [C:\Users\frede\Source\Repos\repro\repro.csproj]
C:\Program Files\dotnet\sdk\1.0.0-preview5-004232\Microsoft.Common.CurrentVersion.targets(1909,5): warning MSB3243: No way to resolve conflict between "System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" and "System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". Choosing "System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" arbitrarily. [C:\Users\frede\Source\Repos\repro\repro.csproj]

How do you resolve the warning?

Alternatively, if you add <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>:

you get this output:

dotnet run
Program.cs(10,9): error CS0103: The name 'ZipFile' does not exist in the current context [C:\Users\frede\Source\Repos\repro\repro.csproj]

The build failed. Please fix the build errors and run again.

All 12 comments

If you open the lib/net46/System.IO.Compression.ZipFile.dll file from the 4.3.0 version of the System.IO.Compression.ZipFile package in ildasm, you will find this:

.class extern forwarder System.IO.Compression.ZipFile
{
  .assembly extern System.IO.Compression.FileSystem
}
.class extern forwarder System.IO.Compression.ZipFileExtensions
{
  .assembly extern System.IO.Compression.FileSystem
}

This means that the class ZipFile (and ZipFileExtensions) is actually implemented in the System.IO.Compression.FileSystem assembly. That assembly is a framework reference of the System.IO.Compression.ZipFile package for .Net 4.6. I think that explains the behavior you're getting and I don't see any issues with it.

I'm assuming that's what DisableImplicitFrameworkReferences is supposed to do, but this is the first time I've heard about it, so I could be wrong.

Consider this scenario:

C:\Users\frede\Source\Repos\repro>dotnet --version
1.0.0-preview5-004232

with repro.csproj:

<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net461</TargetFramework>
    <RuntimeIdentifier>win7-x64</RuntimeIdentifier>
  </PropertyGroup>

  <ItemGroup>
    <Compile Include="**\*.cs" />
    <EmbeddedResource Include="**\*.resx" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="NETStandard.Library" Version="1.6.1" />
  </ItemGroup>

</Project>

and Program.cs:

using System;
using System.IO.Compression;

class Program
{
    static void Main(string[] args)
    {
        ZipFile.CreateFromDirectory("bin\\", "test.zip");
    }
}

Then:

dotnet restore
dotnet build

creates the following warning (which turns into an error in certain cases):

C:\Program Files\dotnet\sdk\1.0.0-preview5-004232\Microsoft.Common.CurrentVersion.targets(1909,5): warning MSB3243: No way to resolve conflict between "System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" and "System.IO.Compression, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089". Choosing "System.IO.Compression, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" arbitrarily. [C:\Users\frede\Source\Repos\repro\repro.csproj]
C:\Program Files\dotnet\sdk\1.0.0-preview5-004232\Microsoft.Common.CurrentVersion.targets(1909,5): warning MSB3243: No way to resolve conflict between "System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" and "System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". Choosing "System.Net.Http, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" arbitrarily. [C:\Users\frede\Source\Repos\repro\repro.csproj]

How do you resolve the warning?

Alternatively, if you add <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>:

you get this output:

dotnet run
Program.cs(10,9): error CS0103: The name 'ZipFile' does not exist in the current context [C:\Users\frede\Source\Repos\repro\repro.csproj]

The build failed. Please fix the build errors and run again.

@ericstj @ianhays any idea? Maybe packaging problem?

As @svick mentioned the package itself does have a frameworkReference to System.IO.Compression.FileSystem:

    <frameworkAssemblies>
      <frameworkAssembly assemblyName="mscorlib" targetFramework=".NETFramework4.6" />
      <frameworkAssembly assemblyName="System.IO.Compression.FileSystem" targetFramework=".NETFramework4.6" />
    </frameworkAssemblies>

If you aren't seeing that at build then I think it's a problem with the how the PackageReference is resolved. With the latest tooling that'd be an MSBuild problem, but it could be SDK (if the SDK targets are getting in the way here).

@cdmihai @eerhardt does this sound like something you're familiar with? If not I can take a look at a repro and route it.

@ericstj I think it's a "sync" problem between the latest version of the SDK/CLI and CoreFX:

  1. Some projects reference NETStandard.Library, even on net461 (like EntityFrameworkCore)
  2. When you build with NETStandard.Library, the latest SDK/CLI gets confused because the same type is defined twice -in the System.IO.Compression.FileSystem that ships with net461 and the one that comes with NETStandard.Library
  3. The only option I've found so far is to enable DisableImplicitFrameworkReferences in your .csproj file, which makes the reference to System.IO.Compression.FileSystem that ships with net461 go away
  4. But because the types in System.IO.Compression.FileSystem that come with NETStandard.Library are implemented as type forwards, this doesn't work.

see dotnet/sdk#514

System.IO.Compression.FileSystem.dll doesn't ship in any package at all. That comes from the desktop targeting pack. System.IO.Compression.ZipFile.dll ships in a package and that is entirely type-forwards that point to System.IO.Compression.FileSystem.dll.

So I took a look at this and it at least in the version of the SDK that I have it looks like it isn't even handling FrameworkAssembly references that come from packages. That's the cause of this issue.

It looks like @natidea added that support with https://github.com/dotnet/sdk/commit/35049cff27b34c8abfb4bed452b4d79bc65ae70a so it's likely a matter of just picking up an SDK with that fix.

Closing this as it is an issue in the SDK, not the packages.

@ericstj Thanks for looking into this! Just to be 100% sure, I downloaded the latest version of the .NET CLI, and tried to compile a similar project (see my .csproj and Class1.cs files below).

Compilation of this method:

public void Foo()
{
    ZipArchive a = new ZipArchive(null);
    ZipFile.CreateFromDirectory("bin\\", "test.zip");
}

still fails when building for net461 using the latest CLI:

dotnet --version
1.0.0-preview5-004275

Without DisableImplicitFrameworkReferences:

dotnet build
[...]
Class1.cs(10,13): error CS0433: The type 'ZipArchive' exists in both 'System.IO.Compression, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' and 'System.IO.Compression, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' [C:\Users\frede\Documents\Visual Studio 2017\Projects\CompressionRepro\CompressionRepro.csproj]

With DisableImplicitFrameworkReferences:

Class1.cs(11,13): error CS0103: The name 'ZipFile' does not exist in the current context [C:\Users\frede\Documents\Visual Studio 2017\Projects\CompressionRepro\CompressionRepro.csproj]

I'm assuming this is what happening:

  • When the framework reference is present, msbuild cannot distinguish between System.IO.Compression versions 4.0 and 4.1
  • When the framework reference is not present, the type forwarding fails (seems logical).

Are you sure @natidea's commit dotnet/sdk@35049cf will fix this?

When the framework reference is present

The ZipArchive bug is totally different: https://github.com/Microsoft/msbuild/issues/1345. In both cases you can see the compiler never sees System.IO.Compression.FileSystem which is where ZipFile lives on desktop. That ZipArchive error is happening because MSBuild is failing to de-dup assemblies that came from packages and those that come from the targeting pack.

I am certain the issue is caused by the lack of FrameworkReference support. I am not certain @natidea's commit will fix it, because I can't easily test his fix. If his fix doesn't address this, then open an issue in the SDK repo.

If you'd like to workaround the bug you can add the following to your project.

    <Reference Include="System.IO.Compression.FileSystem" />

@ericstj Thanks, with DisableImplicitFrameworkReferences set to true and adding an explicit reference to System.IO.Compression.FileSystem as you recommended makes the project compile at least. There's still a build warning:

No way to resolve conflict between "System.IO.Compression, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" and "System.IO.Compression, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089". Choosing "System.IO.Compression, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" arbitrarily.

Anyway, thanks for your help! - it seems this unblocks me and I'll track the upstream bugs to see if they help me get rid of the warnings.

PS: Wouldn't life be easier of System.IO.Compression.ZipFile contained an actual implementation instead of type forwarders on net461?

PS: Wouldn't life be easier of System.IO.Compression.ZipFile contained an actual implementation instead of type forwarders on net461?

Type unification is tricky 馃槈

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jamesqo picture jamesqo  路  3Comments

matty-hall picture matty-hall  路  3Comments

omajid picture omajid  路  3Comments

v0l picture v0l  路  3Comments

EgorBo picture EgorBo  路  3Comments