Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STJ source generation in a WPF project broken #7624

Open
bachratyg opened this issue Mar 15, 2023 · 8 comments
Open

STJ source generation in a WPF project broken #7624

bachratyg opened this issue Mar 15, 2023 · 8 comments
Assignees
Labels
Investigate Requires further investigation by the WPF team.

Comments

@bachratyg
Copy link

Description

Referencing certain NuGets in a Wpf project and using STJ source generation the build breaks.

Reproduction Steps

  1. create new WPF project
  2. add reference to Microsoft.Extensions.Hosting or anything that indirectly depends on System.Text.Json
  3. add the following source:
using System.Text.Json.Serialization;

[JsonSerializable(typeof(string[]))]
public partial class JsonInfo : JsonSerializerContext
{
}
  1. build with dotnet build, VS, whatever

Minimal repro code: https://gist.github.com/bachratyg/09df487726946b05728d5129044ca574

Expected behavior

Should build just fine

Actual behavior

Output from dotnet build

MSBuild version 17.5.0+6f08c67f3 for .NET
  Determining projects to restore...
  Restored <projdir>\WpfApp1.csproj (in 352 ms).
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(9,6): error CS0579: Duplicate 'global::System.CodeDom.Compiler.GeneratedCodeAttribute' attribute [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\JsonStuff.cs(4,22): error CS8646: 'IJsonTypeInfoResolver.GetTypeInfo(Type, JsonSerializerOptions)' is explicitly implemented more than once. [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.String.g.cs(10,102): error CS0102: The type 'JsonInfo' already contains a definition for '_String' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.String.g.cs(14,100): error CS0102: The type 'JsonInfo' already contains a definition for 'String' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.String.g.cs(19,101): error CS0111: Type 'JsonInfo' already defines a member called 'Create_String' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.StringArray.g.cs(10,104): error CS0102: The type 'JsonInfo' already contains a definition for '_StringArray' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.StringArray.g.cs(14,102): error CS0102: The type 'JsonInfo' already contains a definition for 'StringArray' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.StringArray.g.cs(19,103): error CS0111: Type 'JsonInfo' already defines a member called 'Create_StringArray' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.StringArray.g.cs(51,22): error CS0111: Type 'JsonInfo' already defines a member called 'StringArraySerializeHandler' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(13,71): error CS0102: The type 'JsonInfo' already contains a definition for 's_defaultOptions' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(22,42): error CS0102: The type 'JsonInfo' already contains a definition for 's_defaultContext' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(27,40): error CS0102: The type 'JsonInfo' already contains a definition for 'Default' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(32,76): error CS0102: The type 'JsonInfo' already contains a definition for 'GeneratedSerializerOptions' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(35,16): error CS0111: Type 'JsonInfo' already defines a member called 'JsonInfo' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(40,16): error CS0111: Type 'JsonInfo' already defines a member called 'JsonInfo' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(44,78): error CS0111: Type 'JsonInfo' already defines a member called 'GetRuntimeProvidedCustomConverter' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.GetJsonTypeInfo.g.cs(11,86): error CS0111: Type 'JsonInfo' already defines a member called 'GetTypeInfo' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.GetJsonTypeInfo.g.cs(26,141): error CS0111: Type 'JsonInfo' already defines a member called 'global::System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver.GetTypeInfo' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]

Build FAILED.

<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(9,6): error CS0579: Duplicate 'global::System.CodeDom.Compiler.GeneratedCodeAttribute' attribute [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\JsonStuff.cs(4,22): error CS8646: 'IJsonTypeInfoResolver.GetTypeInfo(Type, JsonSerializerOptions)' is explicitly implemented more than once. [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.String.g.cs(10,102): error CS0102: The type 'JsonInfo' already contains a definition for '_String' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.String.g.cs(14,100): error CS0102: The type 'JsonInfo' already contains a definition for 'String' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.String.g.cs(19,101): error CS0111: Type 'JsonInfo' already defines a member called 'Create_String' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.StringArray.g.cs(10,104): error CS0102: The type 'JsonInfo' already contains a definition for '_StringArray' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.StringArray.g.cs(14,102): error CS0102: The type 'JsonInfo' already contains a definition for 'StringArray' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.StringArray.g.cs(19,103): error CS0111: Type 'JsonInfo' already defines a member called 'Create_StringArray' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.StringArray.g.cs(51,22): error CS0111: Type 'JsonInfo' already defines a member called 'StringArraySerializeHandler' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(13,71): error CS0102: The type 'JsonInfo' already contains a definition for 's_defaultOptions' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(22,42): error CS0102: The type 'JsonInfo' already contains a definition for 's_defaultContext' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(27,40): error CS0102: The type 'JsonInfo' already contains a definition for 'Default' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(32,76): error CS0102: The type 'JsonInfo' already contains a definition for 'GeneratedSerializerOptions' [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(35,16): error CS0111: Type 'JsonInfo' already defines a member called 'JsonInfo' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(40,16): error CS0111: Type 'JsonInfo' already defines a member called 'JsonInfo' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.g.cs(44,78): error CS0111: Type 'JsonInfo' already defines a member called 'GetRuntimeProvidedCustomConverter' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.GetJsonTypeInfo.g.cs(11,86): error CS0111: Type 'JsonInfo' already defines a member called 'GetTypeInfo' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
<projdir>\System.Text.Json.SourceGeneration\System.Text.Json.SourceGeneration.JsonSourceGenerator\JsonInfo.GetJsonTypeInfo.g.cs(26,141): error CS0111: Type 'JsonInfo' already defines a member called 'global::System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver.GetTypeInfo' with the same parameter types [<projdir>\WpfApp1_oet233uf_wpftmp.csproj]
    0 Warning(s)
    18 Error(s)

Regression?

Might be related to #6792 (pull #6793, #6799)

Known Workarounds

None that I found. Tried #6680 (comment) as suggested in #6792, didn't work

Impact

Can't use STJ source generator together with libraries that also depend on STJ. E.g. BackgroundService from Microsoft.Extensions.Hosting or stuff from Microsoft.Extensions.Configuration.Json

Configuration

Does not seem to be specific to configuration

dotnet --info
.NET SDK:
 Version:   7.0.202
 Commit:    6c74320bc3

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.19045
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\7.0.202\

Host:
  Version:      7.0.4
  Architecture: x64
  Commit:       0a396acafe

.NET SDKs installed:
  7.0.202 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.15 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 6.0.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 6.0.15 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 7.0.4 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found:
  arm64 [C:\Program Files\dotnet]
    registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\arm64\InstallLocation]
  x86   [C:\Program Files (x86)\dotnet]
    registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables:
  Not set

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download

Other information

No response

@Kuldeep-MS Kuldeep-MS added the Investigate Requires further investigation by the WPF team. label Mar 24, 2023
@Kuldeep-MS Kuldeep-MS self-assigned this Mar 24, 2023
@kevincathcart-cas
Copy link

kevincathcart-cas commented Apr 29, 2024

Analysis of cause

At its core, this stems from having two different versions of the source generator (a type of analyzer) run during a build.

This error happens in CoreCompile as depended upon by _CompileTemporaryAssembly, which is executed in a new subbuild by GenerateTemporaryTargetAssembly.

This task does not use ResolveAssemblies (which avoids duplicates via _HandlePackageFileConflicts). Instead it does a more limited resolution of package assemblies.

What is specifically happening here is that GenerateTemporaryTargetAssembly is passed the complete list of analyzers that the main compilation used. It pre-adds those as <Analyzer> items. It then resolves packages, which potentially adds some analyzers again. Finally, it attempts to deduplicate these with a RemoveDuplicateAnalyzers target, which was added in PR #6799.

That works fine for deduplicating a source generator that only lives in a nuget package, but does not work for deduping a source generator between an in-box version and one from a nuget package.

Temporary workaround

As a temporary workaround, users can add thr following to their csproj (adjust to be correct culture for main XAML files):

<UICulture>en-US</UICulture>

and also add this attribute (with the same value as UICulture property):

[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]

This avoids the using GenerateTemporaryTargetAssembly at the cost of creating a satellite assembly to house the default version of the compiled markup, instead of embedding it into the main assembly.

Proposed solution

Have GenerateTemporaryTargetAssembly add the analyzers it is passed as new <PreresolvedAnalyzer> item type, either instead or in addition to passing them as <Analyzer> items.

Then instead of RemoveDuplicateAnalyzers, we can do:

<Target Name="UsePreresolvedAnalyzers" Condition="'@(PreresolvedAnalyzer)' != ''" BeforeTargets="CoreCompile">
    <ItemGroup>
        <Analyzer Remove="@(Analyzer)" />
        <Analyzer Include="@(PreresolvedAnalyzer)" />
    </ItemGroup>
  </Target>

The result of this is that we end up using the exact same set of source generators as regular build, which seems to be the intention, given that the code was already adding them as <Analyzer> items in the first place.

@HanJaeJoon
Copy link

I have same issue in .NET SDK 8.0.301.
Only temporary workaround works for me.
Thanks anyway.

@franchyd
Copy link

This started occurring for me in .NET 9

@franchyd
Copy link

Related: #10175

@franchyd
Copy link

Analysis of cause

At its core, this stems from having two different versions of the source generator (a type of analyzer) run during a build.

This error happens in CoreCompile as depended upon by _CompileTemporaryAssembly, which is executed in a new subbuild by GenerateTemporaryTargetAssembly.

This task does not use ResolveAssemblies (which avoids duplicates via _HandlePackageFileConflicts). Instead it does a more limited resolution of package assemblies.

What is specifically happening here is that GenerateTemporaryTargetAssembly is passed the complete list of analyzers that the main compilation used. It pre-adds those as <Analyzer> items. It then resolves packages, which potentially adds some analyzers again. Finally, it attempts to deduplicate these with a RemoveDuplicateAnalyzers target, which was added in PR #6799.

That works fine for deduplicating a source generator that only lives in a nuget package, but does not work for deduping a source generator between an in-box version and one from a nuget package.

Temporary workaround

As a temporary workaround, users can add thr following to their csproj (adjust to be correct culture for main XAML files):

<UICulture>en-US</UICulture>

and also add this attribute (with the same value as UICulture property):

[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
This avoids the using GenerateTemporaryTargetAssembly at the cost of creating a satellite assembly to house the default version of the compiled markup, instead of embedding it into the main assembly.

Proposed solution

Have GenerateTemporaryTargetAssembly add the analyzers it is passed as new <PreresolvedAnalyzer> item type, either instead or in addition to passing them as <Analyzer> items.

Then instead of RemoveDuplicateAnalyzers, we can do:

<Target Name="UsePreresolvedAnalyzers" Condition="'@(PreresolvedAnalyzer)' != ''" BeforeTargets="CoreCompile">
    <ItemGroup>
        <Analyzer Remove="@(Analyzer)" />
        <Analyzer Include="@(PreresolvedAnalyzer)" />
    </ItemGroup>
  </Target>

The result of this is that we end up using the exact same set of source generators as regular build, which seems to be the intention, given that the code was already adding them as <Analyzer> items in the first place.

I attempted to use your solution and when doing a dotnet build it works fine but when using dotnet publish the satellite resource is not being published into the publish directory. Any thoughts as to why?

@trovialdo
Copy link

trovialdo commented Mar 20, 2025

Is there any timeline when this will be fixed without the need for the work around?

@franchyd
Copy link

Yes this has now affected two of my projects and my final "workaround" was to completely remove all STJ source generation because I could not get this resolved via the suggested workaround.

@pchaurasia14
Copy link
Member

We're looking into this. Will keep the thread posted on updates.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Investigate Requires further investigation by the WPF team.
Projects
None yet
Development

No branches or pull requests

7 participants