dotnet / wpf

WPF is a .NET Core UI framework for building Windows desktop applications.
MIT License
7.07k stars 1.17k forks source link

Microsoft.WinFX.targets Unknown build error Could not find assembly 'mscorlib' #3465

Open nzain opened 4 years ago

nzain commented 4 years ago

This is essentially a duplicate of the closed https://github.com/dotnet/wpf/issues/3183 ; the ticket was closed, although it was not resolved and I cannot re-open it. @ryalanms told me to reactivate when I see the issue again. Well, it has never been resolved for me. Sorry for the double-issue.

Problem description: WPF core app doesn't build when adding a direct <Reference .../> to an old .Net 2.0 WinCE-compatible framework dll. (Why would you do that? Expensive, proprietary dll from 3rd party, we can't live without it, author has retired)

Actual behavior: dotnet build fails with either (SDK 3.1.401)

C:\Program Files\dotnet\sdk\3.1.401\Sdks\Microsoft.NET.Sdk.WindowsDesktop\targets\Microsoft.WinFX.targets(225,9): 
error MC1000: Unknown build error, 'Could not find assembly 'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac'. 
Either explicitly load this assembly using a method such as LoadFromAssemblyPath() or use a MetadataAssemblyResolver that returns a valid assembly.'

or (SDK 5.0.100-preview.8.20417.9)

C:\Program Files\dotnet\sdk\5.0.100-preview.8.20417.9\Sdks\Microsoft.NET.Sdk.WindowsDesktop\targets\Microsoft.WinFX.targets(240,9):
error MC1000: Unknown build error, 'Could not find assembly 'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac'. 
Either explicitly load this assembly using a method such as LoadFromAssemblyPath() or use a MetadataAssemblyResolver that returns a valid assembly.'

Expected behavior: dotnet build runs fine.

Minimal repro:

@ryalanms said that is should be fixed in 3.1.401, but it is not fixed. He mentioned another version number 16.7.1 - unclear what for. Visual Studio is not involved and I've tested with different MSBuild versions too (the 5.0 preview comes with msbuild 16.8.0.xxx).

nzain commented 4 years ago

Problem is not fixed in the new 3.1.402 dotnet SDK:

C:\Program Files\dotnet\sdk\3.1.402\Sdks\Microsoft.NET.Sdk.WindowsDesktop\targets\Microsoft.WinFX.targets(225,9): 
error MC1000: Unknown build error, 'Could not find assembly 'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac'. 
Either explicitly load this assembly using a method such as LoadFromAssemblyPath() or use a MetadataAssemblyResolver that returns a valid assembly.'
ryalanms commented 4 years ago

Thank you for the report, @nzain. Sorry that the previous fix did not cover this scenario.

Did your project compile with a previous version of .NET Core?

nzain commented 4 years ago

Good question - all my previous experiments with WPF core were rather simple. Thus, I don't know if it worked with an older version. However, I have a netcoreapp3.1 console application working on the exact same dlls for a long time. The <Project Sdk="Microsoft.NET.Sdk"> works fine. Thus, it seems to be a WPF specific issue. After dotnet new wpf the following fails to compile on 3.1.402:

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <UseWPF>true</UseWPF>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="SurvComCE" HintPath="SurvComCE.dll" />
  </ItemGroup>
</Project>

When I create a dotnet new console project, the following works just fine:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="SurvComCE" HintPath="SurvComCE.dll" />
  </ItemGroup>
</Project>
nzain commented 4 years ago

The problem persists with the latest 5.0.100-rc.1.20452.10 release canditate:

C:\Program Files\dotnet\sdk\5.0.100-rc.1.20452.10\Sdks\Microsoft.NET.Sdk.WindowsDesktop\targets\Microsoft.WinFX.targets(240,9): 
error MC1000: Unknown build error, 'Could not find assembly 'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac'. 
Either explicitly load this assembly using a method such as LoadFromAssemblyPath() or use a MetadataAssemblyResolver that returns a valid assembly.'
ryalanms commented 4 years ago

@nzain: Could you provide a project with a reference to a different public .Net 2.0 WinCE-compatible framework dll that reproduces the problem?

nzain commented 4 years ago

@ryalanms please request a private copy vie e-mail (patrick_stalphATtrimble.com).

For the sake of completeness: the problem persists with the latest 5.0.100-rc.2.20479.15 SDK.

nzain commented 3 years ago

@ryalanms I was able to create a Visual Studio 2008 csproj targeting .net v2.0 compact framework to reproduce the issue. The following zip file contains a VS2008 solution and the compiled dll (look for the bin\debug folder). If you want to compile yourself, you have to install Visual Studio 2008 and Microsoft .Net Compact Framework as well. VS2008-WinCE-lib.zip

As soon as you reference the above dll from a WPF Core project (tried today with net5-windows on the new 5.0.100 SDK) you will get the error.

Furthermore, a manual binding redirect for mscorlib does not work. I added the following App.config with no effect:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="mscorlib" culture="neutral" publicKeyToken="969db8053d3322ac" />
        <bindingRedirect oldVersion="2.0.0.0" newVersion="4.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Hope this helps to further diagnose the problem.

nzain commented 3 years ago

@ryalanms can you reproduce the problem with the data linked above?

JensNordenbro commented 3 years ago

I can confirm the same: One dll having a dependency to a thirdparty compact framework assembly that we "cannot easilly replace" gave the same results.

nzain commented 3 years ago

This issue is blocking all potential migration work, there is no workaround up to now, and we are stuck on net 4.8 framework. I understand that developer resources are limited (very limited for WPF especially), but there has been no progress for several month! It would be nice to get some feedback on this at least (can you reproduce it, workaround ideas, milestone expectation).

JensNordenbro commented 3 years ago

@nzain, In our case I managed to stub out our dependency, just mimicing the public api. This ofcourse requires the code not to be the backbone of the application and of course later things needs to be re-implemented unless this is fixed and compatible with net5+. (winforms stuff might not due to reduced api coverage in >= netcore3.1 )

Maybe this approach will work for you, maybe not.... :)

Me, I have given up on the old thirdparty dependencies for CF, and probably we will either contact suppliers for buy-out of source code or just re-implement / replace the dependencies...

nzain commented 3 years ago

The problem remains unresolved with dotnet-sdk-6.0.100-preview.1.21103.13-win-x64 and MS Build 16.9.0-preview-21103-02+198f3f262.

nzain commented 3 years ago

Dotnet 6 Preview 4 - problem remains. @ryalanms were you able to reproduce the problem with the files I shared?

C:\Program Files\dotnet\sdk\6.0.100-preview.4.21255.9\Sdks\Microsoft.NET.Sdk.WindowsDesktop\targets\Microsoft.WinFX.targets(222,9): 
error MC1000: Unknown build error, 
'Could not find assembly 'mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=969db8053d3322ac'. 
Either explicitly load this assembly using a method such as LoadFromAssemblyPath() or use a MetadataAssemblyResolver that returns a valid assembly.'  [D:\Downloads\DotnetCoreIssue\DotnetCoreIssue\DotnetCoreIssue.csproj]
jw-suh commented 3 years ago

Since I have run into the same problem, I want to add the little information I have not yet found in the issues.

The Problem does not occur by creating a WPF Project. A completely empty WPF project will compile. As soon as you add any Page, Window etc. the project breaks.

Find attached an empty WPF library and a WPF library with a Page: EmptyWpfApp.zip NonEmptyWpfApp.zip

I hope this information helps at least narrowing down the error cause.

nzain commented 3 years ago

6.0.100-preview.6.21355.2 does not fix it, just tested it.

ThomasGoulet73 commented 3 years ago

Here's a workaround that you can add to your csproj that you could use until it is fixed:

  <Target Name="RemoveMdpNetApi" BeforeTargets="MarkupCompilePass1">
    <ItemGroup>
      <_TempWPFReference Include="@(ReferencePath)" />
      <ReferencePath Remove="@(ReferencePath)" Condition="'%(ReferencePath.Filename)'=='MdpNetApi'" />
    </ItemGroup>
  </Target>

  <Target Name="RestoreMdpNetApi" AfterTargets="MarkupCompilePass2">
    <ItemGroup>
      <ReferencePath Remove="@(ReferencePath)" />
      <ReferencePath Include="@(_TempWPFReference)" />
    </ItemGroup>
  </Target>

This basically removes the .Net Framework 2.0 CE from being loaded in the markup compilation. The only thing is that you cannot use anything from your .Net Framework 2.0 CE dll inside your xaml.

nzain commented 3 years ago

Thanks @ThomasGoulet73 for suggesting a workaround. Unfortunately, it does not work. I tested with my sample project as posted somewhere above and net5.0.7 SDK. Where did you get that 'MdpNetApi' idea?

jw-suh commented 3 years ago

Hey @nzain sorry for causing this confusion. 'MdeNetApi was the reference I used in my sample somewhere above to reproduce the issue. I guess the workaround should use anyone's specific reference name. I'll give this workaround a go with my sample as soon as I have the time for it.

nzain commented 3 years ago

Thanks @jw-suh for the explanation.. stupid me :) It works with my sample, because the WinCE objects are not used in the UI.

jw-suh commented 3 years ago

Yep, just tried the workaround from @ThomasGoulet73 in my (very limited) sample. And it worked as well. Sadly, I won't be able to test it in my production case any time soon, since we had to move on and found a different solution that did not require any old DLL. For now, I would expect it to work, since the xaml didn't use any part of said DLL.

ryalanms commented 3 years ago

This should have been fixed with https://github.com/dotnet/corefx/pull/42768. I am able to reproduce the failure with @jw-suh's test project.

/cc @dotnet/wpf-developers

ryalanms commented 3 years ago

The assembly reference in the metadata must include 'retargetable' or there is no way for the resolver to know that it has permission to use a newer version of that assembly:

// Metadata version: v4.0.30319 .assembly extern retargetable mscorlib { .publickeytoken = (7C EC 85 D7 BE A7 79 8E ) // |.....y. .ver 2:0:5:0 }

Here is the manifest for the dll used in the repro project. Note that it is missing retargetable.

// Metadata version: v2.0.50727 .module extern MdpApi.dll .assembly extern mscorlib { .publickeytoken = (96 9D B8 05 3D 33 22 AC ) // ....=3". .ver 2:0:0:0 }

ThomasGoulet73 commented 3 years ago

I just tried applying the retargetable flag that @ryalanms talked about and it fixed the bug in the sample @jw-suh provided.

I did that by doing ILDasm -> Add retargetable to mscorlib -> ILAsm.

Here are the steps that I followed (These might vary depending on the assemblies you are trying to modify):

  1. ildasm MdpNetApi.dll /OUT=MdpNetApi.il
  2. Open MdpNetApi.il in a text editor and add retargetable to mscorlib (It's located in the first lines of the file).
  3. ilasm MdpNetApi.il /RESOURCE=MdpNetApi.res /OUTPUT="MdpNetApi_New.dll" /DLL

This is probably not the best solution but since its about supporting a legacy framework and the referenced assembly probably does not get many updates, I'd say that it's good enough.

nzain commented 3 years ago

@ryalanms the fix you mentioned has been merged into the 3.1 release branch in January 2020. When do you expect to see this in a net 5/6 release?

"retargetable" - why do WPF apps require this, but console apps don't?

ryalanms commented 3 years ago

@ericstj: Does a console application allow referencing assemblies built against a different version of mscorlib that do not use the 'retargetable' flag? Should WPF support this?

ericstj commented 3 years ago

Different versions, yes. Retargetable is used to allow assemblies to change public key. By default the loader should permit newer versions of an assembly to satisfy older references. https://github.com/dotnet/runtime/blob/82f7144f791314885c0e4e86f16e579357bfe7e3/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/PathAssemblyResolver.cs#L75 cc @steveharter

"retargetable" - why do WPF apps require this, but console apps don't?

I wouldn't expect the runtime to permit a different public key token without the retargetable bit, perhaps @vitek-karas or @agocke might know if it does (or if it allows this for mscorlib specially).

ryalanms commented 3 years ago

@vitek-karas and @agocke: Is the runtime behavior different?

/cc @SamBent

vitek-karas commented 3 years ago

As far as I can tell the runtime ignores retargetable flag. It will recognize it and store it and if asked can produce the full qualified name of the assembly with the Retargetable=yes section in it. It can also parse such a name. But it doesn't use the value for anything.

Also, runtime ignores public keys when binding assemblies. Meaning:

    AssemblyLoadContext.Default.LoadFromAssemblyPath(@"TestLib.dll");
    // Loaded "TestLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a5aa501ed74f54b5"

    // Notice the different public key
    var asmname = new AssemblyName("TestLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8c18119b32e50707");
    var asmref = AssemblyLoadContext.Default.LoadFromAssemblyName(asmname);
    // No failure.
    // asmref is "TestLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a5aa501ed74f54b5" - so the one already loaded above

Also runtime doesn't verify the strong name in any way. It does persist the information (as seen above, the public keys are part of the assembly names), so it can be used in the app code to verify, but it will not do so itself.

ryalanms commented 3 years ago

Thanks, @vitek-karas. @SamBent: We can discuss this in triage.

ericstj commented 3 years ago

One other good piece of data to gather here: does the compiler permit it? If CSC is also ignoring publicKey it may be fair to ask SRM to relax the constraint. What happens in a normal net5 project where you build against this assembly and try to interact with its API that references types that would live in mscorlib?

djonesCenterEdge commented 2 years ago

@singhashish-wpf has there been any more discussion regarding this?

singhashish-wpf commented 2 years ago

@djonesCenterEdge No, there have not been any further updates on this, However the workarounds are already stated above. Let us know if you think those are not acceptable.

djonesCenterEdge commented 2 years ago

@singhashish-wpf the workarounds stated above don't actually work, as the people who tried them also stated above. We managed to make it work by adding a dependency to System.Runtime.CompilerServices.Unsafe and using msbuild instead of dotnet to build our our solutions.