This was previously reported on GitHub to the MSBuild Team (https://github.com/Microsoft/msbuild/issues/4228) who suggested I open a Visual Studio Support Ticket.
Background
In attempting to reproduce the issue for #4217 I attempted to create a fresh WPF Project to see if I could reproduce it; in doing this I encountered a similar (but I do not believe identical) issue wherein the MainWindow.g.cs was always regenerated.
Steps to reproduce
Please find an attached zip file that contains the project that demonstrates this behavior: WpfAppAlwaysRebuilds.zip
This project was created by:
Creating a new WPF Application within Visual Studio
Modifying the CSPROJ To contain the work around for #1648 as follows
<Target Name="GenerateCompiledExpressionsTempFile">
<!--This is a no-op to overwrite the existing target that ships with MSBuild. When we upgrade to Visual Studio 2019 (MSBuild 16.0) we can remove this. See https://github.com/Microsoft/msbuild/issues/1648-->
</Target>
To reproduce the issue on the command line build the project
msbuild WpfAppAlwaysRebuilds.sln /t:Build
Then launch the Solution in Visual Studio and build you will see this in diganostic verbosity:
Project 'WpfAppAlwaysRebuilds' is not up to date. Input file 's:\temp\markupbug\wpfappalwaysrebuilds\wpfappalwaysrebuilds\objdebug\mainwindow.g.cs' is modified after output file ''.
------ Build started: Project: WpfAppAlwaysRebuilds, Configuration: Debug Any CPU ------
Note that in order to repeat it a second time you MUST delete the contents of the /obj/ folder to start "clean" again. Once it has built in Visual Studio once MSBuild will happily report that it is up to date.
Expected behavior
The expected behavior is that this project will report as "up-to-date"
Actual behavior
The project rebuilds because it determines that it is not "up-to-date"
@livarcocc The Workflow Fix requires the coordination between Dev16; however if you notice bullet 2 I have already worked around this; this is a NEW issue (even after the workflow one is corrected).
Here is the rebuild trigger:
1>Project 'WpfAppAlwaysRebuilds' is not up to date. Input file 'r:\wpfappalwaysrebuilds\wpfappalwaysrebuilds\wpfappalwaysrebuilds\objdebug\mainwindow.g.cs' is modified after output file ''.
If this had been the workflow issue it would have been complaining about a *TemporaryGenerated.cs file.
This issue ends up being the same as the reference issue (although it took me a lot longer to get to that point in the reference issue):
When MSBuild compiles a WPF Application MarkupCompilePass1 is called PRIOR to all Compile inputs being calculated. One such task that adds additional compile items is GenerateTargetFrameworkMonikerAttribute
In Visual Studio GenerateTargetFrameworkMonikerAttribute is called PRIOR to MarkupCompilePass1
Because of the design of MarkupCompilePass1 there is another layer of incremental build caching: it is looking at the number of files used as inputs (as well as taking the hashes of their file names) to determine if it should run again or not. Because this added an additional Compile item in Visual Studio it will always rebuild.
The work around is to apply this into the ProjectFile which will temporarily fix you; but the real fix needs to happen in MSBuild to correctly call GenerateTargetFrameworkMonikerAttribute prior to MarkupCompilePass1:
<PropertyGroup>
<!--This is a hack to try and fix https://github.com/Microsoft/msbuild/issues/4228-->
<MarkupCompilePass1DependsOn>$(MarkupCompilePass1DependsOn);GenerateTargetFrameworkMonikerAttribute</MarkupCompilePass1DependsOn>
</PropertyGroup>
Its unclear who owns this; its either gotta be Visual Studio or the MSBuild team that changes to make this consistent otherwise you will ALWAYS rebuild in WPF.
_This issue has been moved from https://developercommunity.visualstudio.com/content/problem/503048/wpf-application-always-rebuilds-in-visual-studio.html
VSTS ticketId: 826388_
_These are the original issue comments:_
(no comments)
_These are the original issue solutions:_
(no solutions)
Note that {Target}DependsOn properties do not work in "new style" SDK projects if they use implicit imports (the default) so the workaround only applies to classic projects.
What can I do to assist? I do not see the source to MarkupCompilePass1 which is where the bug exists.
In the issues pages there are others who probably are experiencing this root cause; I suspect the following is being burned by some form of this bug: #134
@aolszowka MarkupCompilePass1 is located in PresentationBuildTasks. MS has promised they will open-source it along with the rest of WPF incrementally "in 2019," but here we are, at the end of March, and all we have is still just System.Xaml. 馃晲馃晸馃晼
In short: There's nothing you can do for now but wait. Sorry about that!
We really appreciate everyone filing these issues! I'm sorry we don't have more out yet, but we are working hard on getting more code open sourced. Does you see the same behavior in .NET Framework?
@ryalanms will have more information on when PresentationBuildTasks will be open sourced, but it is coming soon.
@stevenbrix Hi Steven; this report is for the .NET Framework (we're not using Core for this).
I am not sure why I was not notified of your message; but the bug is pretty cut and dry. Let me know what we can do to speed up this process.
Thank you @aolszowka! I think we have all that we need, this is a very nicely detailed bug report :)
For me this issue appeared only when I tried to build a project in Release mode. In Debug mode the issue did not appear.
It turned out the difference was that in Release build I had:
<DocumentationFile>$(OutputPath)\$(AssemblyName).xml</DocumentationFile>
When I removed all parameters (OutputPath and AssemblyName) and used a static path and file name, the issue disappeared. I.e.:
<DocumentationFile>C:\MyOutputPath\MyAssemblyName.xml</DocumentationFile>
UPDATE:
It looks like it was just a temporary fix after editing the WPF project configuration from Visual Studio the recompilation was not happening at each new build. But after the first change in the project I got back to the original case.
@BalintPogatsa I can confirm that this still happens the work around I mentioned is being applied to all of our new WPF Projects.
The original case we feel is detailed enough if there is something we can help clarify please let us know.
I just wanted to say that this issue is still happening for me on VS 2019.4.1. . The workaround mentioned above seems to working, but just when I directly modify the .csproj files. Is there a way to apply this workaround to all .csproj files? I tried setting it on the Microsoft.CSharp.x64.user.props, but that doesn't seem to have any effect.
@KonanM I can tell you for us we just had to write a tool that we run on our CI to insert this on a per CSPROJ File basis.
One thing that might be possible to do is have a custom .targets file that you import, but based on your message above it seems like that didn't work (are you use that the Microsoft.CSharp.x64.user.props is imported? you can use https://github.com/KirillOsenkov/MSBuildStructuredLog to validate one way or another).
Still fails for us in VS 2019 16.6.3 which is a bummer.
As my company works to migrate a very large solution to .NET Core/.NET 5, I'm finding this to be a significant issue. My experience is that this rebuild behavior always happens with all .xaml files:
dotnet new wpf
dotnet build
dotnet build
The second dotnet build always builds - it never reports up to date. I just tested this against the recent release of .NET 5. This forces most of our projects to rebuild no matter what change we make. That's a serious productivity issue and a regression against .NET Framework.
We should get rid of MarkupCompilePass1/2 and GenerateTemporaryAssembly and move this entire logic to Source Generators.
Most helpful comment
We should get rid of MarkupCompilePass1/2 and GenerateTemporaryAssembly and move this entire logic to Source Generators.