Wpf: WPF assemblies are incompatible with each other in 3.0.0-alpha-27128-4

Created on 24 Dec 2018  路  14Comments  路  Source: dotnet/wpf

  • .NET Core Version: 3.0.0-alpha-27128-4
  • Windows version: 10.0.17763.0
  • Does the bug reproduce also in WPF for .NET Framework 4.8?: No

In dotnet\sharedMicrosoft.WindowsDesktop.App\3.0.0-alpha-27128-4, PresentationCore.dll references System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.

But the System.Xaml.dll assembly in that folder has a different public key token (31bf3856ad364e35).

So when you use Roslyn to compile a WPF app by referencing these assemblies, you end up with errors like this:

The type 'IQueryAmbient' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.

I don't these errors in Visual Studio, so I presume Visual Studio must be relying on referencing assemblies drawn from some other place. But as I understand, reference assemblies aren't mandatory. It should still be possible to compile code against real assemblies.

issue-type-bug

Most helpful comment

Key in desktop is b77a5c561934e089. Key in internal build is (correctly) the same.
Key in this repo is 31bf3856ad364e35.

The key here is wrong. It must match desktop to permit binary reuse of desktop assemblies on Core. If you change the reference assembly to match what you have in the implementation here (and not desktop) you will start to see compiler errors when folks reuse desktop assemblies in .NETCore.

This must be fixed, you need to set StrongNameKeyId=ECMA in the System.Xaml project.

Moreover you need to run APICompat between your reference assemblies and implementation as well as APICompat between desktop and core to ensure you don't introduce more of these problems.

All 14 comments

I believe that reference assemblies are in general mandatory. I don't think we support compiling against runtime assemblies in general (if reference assemblies are available). At minimum compiling against runtime assemblies causes some interesting problems in certain scenarios, so I would personally recommend to avoid that.
For general .NET and also for WPF or any other framework.

Could you elaborate on what the interesting problems are? Right now I'm writing LINQPad for .NET Core 3. LINQPad uses Roslyn to compile queries against the runtime assemblies, as it has always done with .NET Framework. I would like to keep LINQPad.exe small, and have it work with whatever version of .NET Core is installed on the machine. It's a lightweight tool and I'd rather not have to embed 300+ reference assemblies (and then have it locked into a particular version of .NET Core).

Your statement that reference assemblies are mandatory seems to imply that Roslyn is effectively useless in .NET Core without a whole additional set of baggage. In other words, if we want to dynamically generate an assembly at runtime, it's not enough to reference and ship Microsoft.CodeAnalysis. We also need to (somehow) ship a set of reference assemblies. Is there any guidance on the procedure here? (The problem is compounded by not having Reflection.Emit as an alternative, because the option to save assemblies is not available in .NET Core.)

Also, is there any explanation on the rationale for having the wrong public key on some .NET Core assemblies? Is it to deliberately force us into using reference assemblies?

I think what you're seeing is due to our current split build system.

Currently, the System.Xaml reference assembly is built in a private repository while the lib assembly is built from this repository. These are different build systems and as we were onboarding to our new system, we ran into some issues that were more easily solved by leaving the reference assembly build behind.

Eventually, we're going to have everything build from the same place and build system and we shouldn't have this issue.

Thanks for reporting this, I'm going to leave it open for now and this should be resolved as we move more completely into our new build system.

@albahari over the years I have seen people running into troubles on both .NET Framework and .NET Core without reference assemblies. Especially when there is mix of assemblies referencing both - reference assemblies and runtime assemblies. Take my note as "you should be extra careful, you may run into troubles eventually".
I don't know about exact mechanics how to reship reference assemblies, but I expect that apps which bundle Roslyn may consider doing the same thing as .NET Core SDK and reship the reference assemblies.
I expect that Roslyn team will have more accurate guidance what to do and what is recommended from their point of view.

@albahari one problem you can encounter compiling against runtime desktop framework is that the user may have installed inplace updates of newer versions (than the one your application was compiled against) which may have moved types around. If your script compiles against your application and the runtime desktop version you may suddenly see the same type appear in two assemblies and fail to compile scripts.

We had that happen for System.ValueTuple which was moved into the framework at some point. If we compiled our application against a certain framework version then we had some machines where ValueTuple was loaded twice and scripts failed to compile.

I never did an in-depth analysis of the problem, but I believe it has to do with the tricks the framework pulls to replace System.ValueTuple from an external assembly with an internal version. If I understood it correctly Roslyn isn't aware of those "magic redirections" built into the runtime framework.

It would be great to organize documenting some guidance on this problem, as apparently with .NET Core 3 its becoming more complicated again.

@weltkante I thought that one of the main benefits of the transition from .NET Framework to .NET Core was a move away from in-place framework updates that cause subtle breaking changes, in favour of releasing new versions of the framework that run side-by-side.

Or by in-place updates, are you referring to updating dependencies other than the framework?

@albahari Oh I thought you wanted to know how you can run into problems when you compile against runtime assemblies on the desktop framework, just was giving an example for that.

I didn't do much Roslyn + .NET Core yet so I don't have any practical examples. But since they are handcrafting their reference assemblies in corefx (probably for a reason) there might be "intentional lies" which you are missing if you compile against runtime assemblies.

Key in desktop is b77a5c561934e089. Key in internal build is (correctly) the same.
Key in this repo is 31bf3856ad364e35.

The key here is wrong. It must match desktop to permit binary reuse of desktop assemblies on Core. If you change the reference assembly to match what you have in the implementation here (and not desktop) you will start to see compiler errors when folks reuse desktop assemblies in .NETCore.

This must be fixed, you need to set StrongNameKeyId=ECMA in the System.Xaml project.

Moreover you need to run APICompat between your reference assemblies and implementation as well as APICompat between desktop and core to ensure you don't introduce more of these problems.

If you change the reference assembly to match what you have in the implementation here (and not desktop) you will start to see compiler errors when folks reuse desktop assemblies in .NETCore.

Looks like that is what happened:

位 sn  -T "C:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\3.0.0-preview4-27605-09\ref\netcoreapp3.0\System.Xaml.dll"

Microsoft (R) .NET Framework Strong Name Utility  Version 4.0.30319.0
Copyright (c) Microsoft Corporation.  All rights reserved.

Public key token is 31bf3856ad364e35

@vatsan-madhavan Is the reference assembly built from this repo or from dotnet-trusted?

@nguerrera: the reference assembly for System.Xaml is built from this repo. System.Xaml no longer exists in dotnet-trusted and all reference assembly projects have been deleted.

OK, I believe fixing this by setting StrongNameKeyId=ECMA as mentioned in https://github.com/dotnet/wpf/issues/208#issuecomment-459795224 will also fix #508.

While you鈥檙e at it turn on APICompat.

This was fixed as part of https://github.com/dotnet/wpf/pull/515. @rladuca is working on incorporating ApiCompat - tracked by #724

Was this page helpful?
0 / 5 - 0 ratings