Skip to content

Conversation

@drewnoakes
Copy link
Member

@drewnoakes drewnoakes commented Nov 20, 2025

The IfDifferent value is valid in modern MSBuild:

https://github.com/dotnet/msbuild/blob/863bbb87f1b5cbf792fbefb7005ff83bb8af0e4b/src/MSBuild/MSBuild/Microsoft.Build.CommonTypes.xsd#L776

Without this change, attempting to use it causes an error in the FUTDC:

=====================
20-Nov-25 11:17:37
LimitedFunctionality
System.AggregateException: Project system data flow 'UpToDateCheckConfiguredInputDataSource: 36760100' closed because of an exception.
CopyToOutputDirectory should be Always or PreserveNewest, not IfDifferent
---> (Inner Exception #0) Microsoft.Assumes+InternalErrorException: CopyToOutputDirectory should be Always or PreserveNewest, not IfDifferent
   at Microsoft.Assumes.Fail(String message)
   at Microsoft.VisualStudio.ProjectSystem.VS.UpToDate.CopyItem.<GetCopyType>g__ParseCopyType|15_0(String value)
   at Microsoft.VisualStudio.ProjectSystem.VS.UpToDate.CopyItem.GetCopyType(IImmutableDictionary`2 metadata)
   at Microsoft.VisualStudio.ProjectSystem.VS.UpToDate.UpToDateCheckImplicitConfiguredInput.<>c.<Update>b__76_24(KeyValuePair`2 pair)
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at System.Collections.Immutable.ImmutableArray.CreateRange[T](IEnumerable`1 items)
   at Microsoft.VisualStudio.ProjectSystem.VS.UpToDate.UpToDateCheckImplicitConfiguredInput.<>c__DisplayClass76_0.<Update>g__UpdateCopyData|9()
   at Microsoft.VisualStudio.ProjectSystem.VS.UpToDate.UpToDateCheckImplicitConfiguredInput.Update(IProjectSubscriptionUpdate jointRuleUpdate, IProjectSubscriptionUpdate sourceItemsUpdate, IProjectItemSchema projectItemSchema, IProjectCatalogSnapshot projectCatalogSnapshot)
   at Microsoft.VisualStudio.ProjectSystem.VS.UpToDate.UpToDateCheckImplicitConfiguredInputDataSource.<>c__DisplayClass12_0.<<LinkExternalInput>g__TransformAsync|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.VisualStudio.ProjectSystem.TransformBlockSlim`2.TransformBlockSlimAsync.<ProcessInputAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.VisualStudio.ProjectSystem.DataReceivingBlockSlim`1.<ProcessInputQueueAsync>d__5.MoveNext()
<--- (Inner Exception #0) 
===================

This change adds support for it. The FUTDC already treats "Always" in the same way as "IfDifferent" (which helps performance a lot), so the user wouldn't notice a difference between these two options for builds in VS, but there would be a different for command-line builds.

EDIT Showing this in the properties window was moved to a separate PR given the below discussion: #9861

@drewnoakes drewnoakes added this to the 18.3 milestone Nov 20, 2025
@drewnoakes drewnoakes requested a review from a team as a code owner November 20, 2025 10:53
@drewnoakes drewnoakes added the Feature-Up-to-date Build up-to-date check that avoids shelling out to MSBuild unless necessary. label Nov 20, 2025
Copy link
Member

@Evangelink Evangelink left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @drewnoakes <3

@drewnoakes drewnoakes requested a review from baronfel November 20, 2025 11:18
@baronfel
Copy link
Member

How should I think about project-system changes like this in the context of differing SDK capabilities? I very strongly expect copies and publishes to break in silent ways on any SDK that doesn't include Jan's changes (and more) - so turning this on for any SDK < 10.0.200 would be something I would push back on.

@drewnoakes
Copy link
Member Author

@baronfel it might be possible to change the set of options we show to the user based on their SDK. It's a bit more work. But even if one dev is using a new SDK, they may have colleagues on the team who use an older SDK. And older versions of VS don't understand this option and will fail on it.

The safest option is to break this PR up into different parts: the part that handles the value gracefully, and the part that makes it easier for users to discover and use this new value.

The `IfDifferent` value is valid in modern MSBuild:

https://github.com/dotnet/msbuild/blob/863bbb87f1b5cbf792fbefb7005ff83bb8af0e4b/src/MSBuild/MSBuild/Microsoft.Build.CommonTypes.xsd#L776

Without this change, attempting to use it causes an error in the FUTDC:

```
=====================
20-Nov-25 11:17:37
LimitedFunctionality
System.AggregateException: Project system data flow 'UpToDateCheckConfiguredInputDataSource: 36760100' closed because of an exception.
CopyToOutputDirectory should be Always or PreserveNewest, not IfDifferent
---> (Inner Exception #0) Microsoft.Assumes+InternalErrorException: CopyToOutputDirectory should be Always or PreserveNewest, not IfDifferent
   at Microsoft.Assumes.Fail(String message)
   at Microsoft.VisualStudio.ProjectSystem.VS.UpToDate.CopyItem.<GetCopyType>g__ParseCopyType|15_0(String value)
   at Microsoft.VisualStudio.ProjectSystem.VS.UpToDate.CopyItem.GetCopyType(IImmutableDictionary`2 metadata)
   at Microsoft.VisualStudio.ProjectSystem.VS.UpToDate.UpToDateCheckImplicitConfiguredInput.<>c.<Update>b__76_24(KeyValuePair`2 pair)
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at System.Collections.Immutable.ImmutableArray.CreateRange[T](IEnumerable`1 items)
   at Microsoft.VisualStudio.ProjectSystem.VS.UpToDate.UpToDateCheckImplicitConfiguredInput.<>c__DisplayClass76_0.<Update>g__UpdateCopyData|9()
   at Microsoft.VisualStudio.ProjectSystem.VS.UpToDate.UpToDateCheckImplicitConfiguredInput.Update(IProjectSubscriptionUpdate jointRuleUpdate, IProjectSubscriptionUpdate sourceItemsUpdate, IProjectItemSchema projectItemSchema, IProjectCatalogSnapshot projectCatalogSnapshot)
   at Microsoft.VisualStudio.ProjectSystem.VS.UpToDate.UpToDateCheckImplicitConfiguredInputDataSource.<>c__DisplayClass12_0.<<LinkExternalInput>g__TransformAsync|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.VisualStudio.ProjectSystem.TransformBlockSlim`2.TransformBlockSlimAsync.<ProcessInputAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.VisualStudio.ProjectSystem.DataReceivingBlockSlim`1.<ProcessInputQueueAsync>d__5.MoveNext()
<--- (Inner Exception #0)
===================
```

This change adds support for it. The FUTDC already treats "Always" in the same way as "IfDifferent" (which helps performance a lot), so the user wouldn't notice a difference between these two options for builds in VS, but there would be a different for command-line builds.
@drewnoakes drewnoakes force-pushed the support-if-different-copy-type branch from 3751490 to 5ac2276 Compare November 21, 2025 12:58
@drewnoakes
Copy link
Member Author

I removed the change to the project properties and will create a separate PR to track that. This PR now only teaches the FUTDC about this option to prevent the original exception.

@drewnoakes drewnoakes changed the title Support CopyToOutputDirectory="IfDifferent" FUTDC support for CopyToOutputDirectory="IfDifferent" Nov 21, 2025
@drewnoakes drewnoakes merged commit c9cae8b into dotnet:main Nov 21, 2025
5 checks passed
@drewnoakes drewnoakes deleted the support-if-different-copy-type branch November 21, 2025 13:19
@dotnet-policy-service dotnet-policy-service bot modified the milestones: 18.3, 18.1 Nov 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature-Up-to-date Build up-to-date check that avoids shelling out to MSBuild unless necessary.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants