Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
$(CollectUpToDateCheckInputDesignTimeDependsOn);
ResolveStaticWebAssetsConfiguration;
ResolveProjectStaticWebAssets;
ResolveReferencedProjectsStaticWebAssetsConfiguration;
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

Adding ResolveReferencedProjectsStaticWebAssetsConfiguration to the design-time FUTDC input chain means this target will now run frequently during design-time builds. That target currently writes $(StaticWebAssetReferencesUpToDateCheckManifestPath) using WriteLinesToFile with Overwrite="false" (append) in Microsoft.NET.Sdk.StaticWebAssets.References.targets, which can cause the manifest file to grow with duplicate/stale entries across repeated evaluations and potentially degrade FUTDC performance. Consider adjusting the referenced target to overwrite (or otherwise de-dupe) the file when it is generated during design-time evaluation so the tracked inputs remain bounded and accurate.

Suggested change
ResolveReferencedProjectsStaticWebAssetsConfiguration;

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

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

I wanted to have this change as a separate PR (as it is an independent problem, only made more noticeable by the primary fix here). However, added it to this PR.

CollectStaticWebAssetInputsDesignTime;
</CollectUpToDateCheckInputDesignTimeDependsOn>
<CollectUpToDateCheckOutputDesignTimeDependsOn>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<WriteLinesToFile Condition="'$(BuildingInsideVisualStudio)' == 'true'"
File="$(StaticWebAssetReferencesUpToDateCheckManifestPath)"
Lines="@(_ReferenceManifestPath)"
Overwrite="false"
Overwrite="true"
WriteOnlyWhenDifferent="true" />

<MergeConfigurationProperties
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,59 @@ public void CollectUpToDateCheckInputOutputsDesignTime_IncludesReferencedProject
Path.GetFileName(outputFiles[0]).Should().Be("staticwebassets.build.json");
}

[Fact]
public void CollectUpToDateCheckInputOutputsDesignTime_IncludesReferencedProjectsManifests_WithCleanObjFolder()
{
// Arrange - this test validates the fix for dotnet/aspnetcore#65738.
// The design-time target must resolve referenced project manifests even
// when no prior build has run (clean obj folder), because VS evaluates
// FUTDC inputs on initial project load before any build occurs.
var testAsset = "RazorAppWithP2PReference";
ProjectDirectory = AddIntrospection(CreateAspNetSdkTestAsset(testAsset));

var build = CreateBuildCommand(ProjectDirectory, "AppWithP2PReference");
var classLibBuild = CreateBuildCommand(ProjectDirectory, "ClassLibrary");

// Do NOT run a build first - go straight to design-time targets on a clean obj folder.
var msbuild = CreateMSBuildCommand(
ProjectDirectory,
"AppWithP2PReference",
"ResolveStaticWebAssetsConfiguration;ResolveProjectStaticWebAssets;ResolveReferencedProjectsStaticWebAssetsConfiguration;CollectStaticWebAssetInputsDesignTime;CollectStaticWebAssetOutputsDesignTime");

msbuild.Execute("/p:DesignTimeBuild=true", "/p:BuildingInsideVisualStudio=true", "/bl:design.binlog").Should().Pass();

// Verify the dependency chain wiring: CollectUpToDateCheckInputDesignTimeDependsOn
// must include ResolveReferencedProjectsStaticWebAssetsConfiguration so that VS
// invokes it during design-time evaluation. If this wiring is reverted, the
// references file would not exist on a clean obj folder and the FUTDC inputs
// would be empty.
var depChainFilePath = Path.Combine(build.GetIntermediateDirectory().FullName, "StaticWebAssetsDependsOn.txt");
var depChainMsbuild = CreateMSBuildCommand(
ProjectDirectory,
"AppWithP2PReference",
"ReportDependsOn");
depChainMsbuild.Execute(
"/p:DesignTimeBuild=true",
"/p:BuildingInsideVisualStudio=true",
$"""/p:_ReportDependsOnOutputPath={depChainFilePath}""").Should().Pass();
new FileInfo(depChainFilePath).Should().Exist();
var depChain = File.ReadAllText(depChainFilePath);
depChain.Should().Contain("ResolveReferencedProjectsStaticWebAssetsConfiguration");

// The referenced project's manifest path should be included as a FUTDC input
// even though no prior build has created the references upToDateCheck file.
var inputFilePath = Path.Combine(build.GetIntermediateDirectory().FullName, "StaticWebAssetsUTDCInput.txt");
new FileInfo(inputFilePath).Should().Exist();
var inputFiles = File.ReadAllLines(inputFilePath);
inputFiles.Should().Contain(Path.Combine(classLibBuild.GetIntermediateDirectory().FullName, "staticwebassets.build.json"));

var outputFilePath = Path.Combine(build.GetIntermediateDirectory().FullName, "StaticWebAssetsUTDCOutput.txt");
new FileInfo(outputFilePath).Should().Exist();
var outputFiles = File.ReadAllLines(outputFilePath);
outputFiles.Should().ContainSingle();
Path.GetFileName(outputFiles[0]).Should().Be("staticwebassets.build.json");
}

private static MSBuildCommand CreateMSBuildCommand(TestAsset testAsset, string relativeProjectPath, string targets)
{
return (MSBuildCommand)new MSBuildCommand(testAsset.Log, targets, testAsset.TestRoot, relativeProjectPath)
Expand Down Expand Up @@ -156,8 +209,18 @@ private static TestAsset AddIntrospection(TestAsset testAsset)
Encoding="UTF-8"
/>
</Target>
"""
));
"""));
project.Document.Root.LastNode.AddAfterSelf(
XElement.Parse("""
<Target Name="ReportDependsOn">
<WriteLinesToFile
File="$(_ReportDependsOnOutputPath)"
Lines="$(CollectUpToDateCheckInputDesignTimeDependsOn)"
Overwrite="true"
Encoding="UTF-8"
/>
</Target>
"""));
});
}
}
Loading