.NET 6 is doing some strange things to the names of my projects...

A little over a month ago, I found myself greeting the new day with my usual fairly-cheery demeanor by taking a quick look at all the latest news and goings-on in the tech world.

Lo and behold! I was greeted with grand news indeed: the release of a new version of .NET, along with Visual Studio 2022. Well, to be honest, I really was just starting to get nice and comfy with .NET 5, but one must keep up with the times!

I immediately set forth to acquire this newly sanctified development stack with the intention to eventually port my Bad Echo technologies and related applications to the new version, which were, of course, previously running on .NET 5 and being developed using Visual Studio 2019.

It was my plan to continue working on my Bad Echo tech within my Visual Studio 2019 environment, comfortably and at my leisure, while examining the new platform and IDE. Only when all the right chips were in place would I be making the move to the new .NET version…

Alas, this was not to be.

XAML Compiler Errors in VS 2019 After Upgrade

With Visual Studio 2022 being a separate product from Visual Studio 2019, as well as .NET 6 being a separate platform from .NET 5, one might expect a small amount of insulation between the two environments. In other words, you would hope that installing the latest and the greatest wouldn’t impact your current development environment.

Sadly, my code, which compiled just fine in VS 2019 before the upgrade, started to throw errors in VS 2019 after installing VS 2022 and .NET 6.

This was very strange, as my code was still targeting .NET 5…

The particular error I was getting was centered around some keyed resources I had defined in the Extensibility framework for Vision, the game overlay application I created to provide on-demand visual data for Omnified games.

Vision comprises several plugins, each corresponding to various Omnified systems. The Extensibility framework for Vision, found in BadEcho.Vision.Extensibility.dll, is a unifying library which all these plugins reference so they can all speak the same lingo and all walk the same walk.

And one of the ways these plugins walk the same walk is by having shared visual elements, such as coloring, etc. These common theme elements are defined in a resource dictionary in this particular Extensibility library.

Now, whenever I define a WPF resource in a common DLL that I expect other assemblies to reference, I like a bit more assurance than just an easily misspelled string name for the key.

Type safety!

That’s what I like. And I achieve this in a similar way (though not exactly the same way, but I digress as that leads to a whole other discussion) we reference the various system colors exposed by WPF’s built-in SystemColors class.

To make use of these system colors, we reference them via the x:Static markup extension — e.g., {x:Static SystemColors.HighlightBrush}.

If I spell the name of this “resource” wrong, we’ll get a compiler error. Not so with a simple string-based key name; we won’t know about any issues with those until runtime!

That kind of assurance one gets when interfacing with static resource keys such as those exposed by SystemColors is what I like to have with my own shared resources whose consumers are external and potentially many. Unfortunately, the .NET 6 install wasn’t having any of that!

The Problem Code

I won’t go into detail how my static resource key names work, all we need to understand is that they work like any other kind of value one might assign to the key of a resource, with the added benefit that compilation fails if any kind of fat-fingering (i.e., mistyping-of-the-key) occurs.

Prior to installing Visual Studio 2022 and .NET 6, the following code was compiling just fine:

<SolidColorBrush x:Key="{x:Static t:Brushes.TextForegroundKey}" 
                 Color="{StaticResource {x:Static t:Colors.TextColorKey}}"
                 f:Freeze="True" 
                 />
<SolidColorBrush x:Key="{x:Static t:Brushes.CriticalTextForegroundKey}" 
                 Color="{StaticResource {x:Static t:Colors.CriticalTextColorKey}}"
                 f:Freeze="True" 
                 />

<SolidColorBrush x:Key="{x:Static t:Brushes.OutlinedTextStrokeKey}"
                 Color="{StaticResource {x:Static t:Colors.OutlineColorKey}}"
                 f:Freeze="True"
                 />

<SolidColorBrush x:Key="{x:Static t:Brushes.FadedOutlinedTextStrokeKey}"
                 Color="{StaticResource {x:Static t:Colors.FadingOutlineColorKey}}"
                 f:Freeze="True"
                 />

After the update, the same code failed (again, in Visual Studio 2019) with the following errors:

1>C:\src\BadEcho\src\Vision.Extensibility\AnchorPointLocation.cs(14,1,45,2): 
warning CA1707: Remove the underscores from assembly name 
BadEcho.Vision.Extensibility_po1jwjdd_wpftmp

1>C:\src\BadEcho\src\Vision.Extensibility\Themes\Resources\Coloring.xaml(25,22): 
error MC3050: Cannot find the type 'Colors'. Note that type names are case sensitive.

1>C:\src\BadEcho\src\Vision.Extensibility\Themes\Resources\VisionTitleTextStyle.xaml(19,33): 
error MC3050: Cannot find the type 'Brushes'. Note that type names are case sensitive.
1>    1 Warning(s)
1>    2 Error(s)

First of all, what is going on with that first warning with the malformed project name? It looks like the compiler literally swallowed my project and involuntarily regurgitated it back up in a corrupted form.

Secondly, the actual errors at hand, which indicate that the compiler is unable to find the types Colors and Brushes referenced in the file, are also problematic as these types are defined in the very same assembly that this ResourceDictionary exists in.

Very strange…

.NET 5, But Not Completely .NET 5

I first wanted to see how an install of .NET 6 and Visual Studio 2022, both different products from Visual Studio 2019, could cause this. I turned on detailed diagnostic logging with MSBuild in Visual Studio 2019, and saw something very interesting right away:

1>Target MarkupCompilePass2:
1>  Task "Message" skipped, due to false condition; ('$(MSBuildTargetsVerbose)'=='true') was 
evaluated as (''=='true').
1>  Using "MarkupCompilePass2" task from assembly 
"C:\Program Files\dotnet\sdk\6.0.100\Sdks\Microsoft.NET.Sdk.WindowsDesktop\tools\net472\
PresentationBuildTasks.dll".
1>  Task "MarkupCompilePass2"
1>
1>    Microsoft (R) Build Task 'MarkupCompilePass2' Version '6.0.21.52301'.
1>    Copyright (C) Microsoft Corporation 2005. All rights reserved.
1>
1>    Current project directory is 'C:\src\BadEcho\src\Vision.Extensibility\'.
1>    Preparing for the markup compilation...
Well, this is a bit alarming…

Vision‘s Extensibility project was targeting .NET 5, yet for some reason it was using .NET 6’s XAML markup compiler. Not sure if this is intentional on Microsoft’s part; it’s difficult to see it as anything other than a bug.

Well, even if we’ve determined that our .NET 5 project is using an incorrect version of the markup compiler, this doesn’t solve our particular problem at hand, which will surely remain a problem upon transitioning the codebase so it targets .NET 6.

Indeed, after doing so, this error persisted.

Temporary Target Assembly Gibberish

Not much further up the build log from where I just posted, we see the task GenerateTemporaryTargetAssembly being executed. It was my assumption that this particular task was responsible for creating those *_wpftmp.csproj malformations of my Extensibility’s project file name.

It was also my assumption that perhaps these temporary assemblies, project names, or what-have-you were also perhaps in part responsible for our inability to resolve types defined in the same assembly within our ResourceDictionary XAML markup.

So why were these temporary assemblies being generated? The same reason anything strange happens in the land of MSBuild: because of an unexpected MSBuild property of course!

Deep within the bowels of MSBuild, exists a property known as <IncludePackageReferencesDuringMarkupCompilation/>, which is assigned a Boolean value. I suppose the option does exactly what its name indicates, and that supposition will have to do, since documentation is a bit scant in this particular area.

Apparently, this setting defaulted to false in .NET 5.0, however that is no longer the case in .NET 6.0. Indeed, it is on by default, and it would appear that this option, when enabled, is what is responsible for generating all those temporary assemblies and causing my error.

The Temporary Assembly Mayhem Fix

Things were definitely better off as they were before. Not sure what this newly-enabled option is supposed to do, but I definitely don’t like it.

To correct the issue, and once again bring about lovely error-free compiles, I stuck the following into the existing root <PropertyGroup/> in my repository’s Directory.build.props file:

<PropertyGroup>
  .
  .
  <IncludePackageReferencesDuringMarkupCompilation>
	  false
  </IncludePackageReferencesDuringMarkupCompilation>
  .
  .
</PropertyGroup>

And all was well.

Hope this saves someone else out there a headache or two!