Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
d4c1054
Add Target Framework version to website metaprojects
Jan 6, 2026
bc87445
Use template strings for clarity
Jan 6, 2026
b5161c2
Merge branch 'dotnet:main' into bugfix/fix-asp-websites-failing-to-re…
johnazule Jan 18, 2026
e9499d6
Fix ASP.NET WebSite projects to copy netstandard.dll facade
JanProvaznik Jan 19, 2026
f50c1cb
Add ChangeWave protection and 4.7.1+ restriction for ASP.NET netstand…
JanProvaznik Feb 2, 2026
3635d10
Add AspNetClean parameter for Rebuild target
JanProvaznik Feb 2, 2026
e25d08d
Add ChangeWave 18.5 definition
JanProvaznik Feb 2, 2026
2943121
Merge branch 'main' into fix/aspnet-website-netstandard-facades
JanProvaznik Feb 2, 2026
dd56c14
Revert "Add AspNetClean parameter for Rebuild target"
JanProvaznik Feb 2, 2026
2fac535
Add missing Wave18_4 definition from merge
JanProvaznik Feb 2, 2026
c0e6d93
Address PR review comments
JanProvaznik Feb 2, 2026
0f4b95f
Merge branch 'main' into fix/aspnet-website-netstandard-facades
JanProvaznik Feb 5, 2026
e347b19
reintroduce changewave 18_5
JanProvaznik Feb 5, 2026
2884fd0
Merge main and update ChangeWave from 18.5 to 18.6
JanProvaznik Mar 10, 2026
aea7f50
Merge branch 'main' into fix/aspnet-website-netstandard-facades
JanProvaznik Mar 19, 2026
de238d3
Update ChangeWave from 18.6 to 18.7 for ASP.NET netstandard fix
JanProvaznik Apr 7, 2026
2dfff4b
Merge branch 'main' into fix/aspnet-website-netstandard-facades
JanProvaznik Apr 7, 2026
62cf2fe
Merge branch 'main' into fix/aspnet-website-netstandard-facades
JanProvaznik Apr 7, 2026
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
3 changes: 3 additions & 0 deletions documentation/wiki/ChangeWaves.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ Change wave checks around features will be removed in the release that accompani

## Current Rotation of Change Waves

### 18.7
- [Fix ASP.NET WebSite projects to resolve netstandard2.0 dependencies](https://github.com/dotnet/msbuild/pull/13058) - Pass TargetFrameworkVersion to RAR task and copy netstandard.dll facade for .NET Framework 4.7.1+ web projects.

### 18.6
- [AbsolutePath.GetCanonicalForm optimization - avoid expensive Path.GetFullPath calls when paths don't need canonicalization](https://github.com/dotnet/msbuild/pull/13369)
- [TaskHostTask forwards request-level global properties (e.g. MSBuildRestoreSessionId) to out-of-proc TaskHost in -mt mode](https://github.com/dotnet/msbuild/pull/13443)
Expand Down
59 changes: 58 additions & 1 deletion src/Build/Construction/Solution/SolutionProjectGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
Expand Down Expand Up @@ -418,6 +418,7 @@ private static void AddTasksToCopyAllDependenciesIntoBinDir(
string copyLocalFilesItemName = referenceItemName + "_CopyLocalFiles";
string targetFrameworkDirectoriesName = GenerateSafePropertyName(project, "_TargetFrameworkDirectories");
string fullFrameworkRefAssyPathName = GenerateSafePropertyName(project, "_FullFrameworkReferenceAssemblyPaths");
string dependsOnNetStandardPropertyName = GenerateSafePropertyName(project, "_DependsOnNETStandard");
string destinationFolder = String.Format(CultureInfo.InvariantCulture, @"$({0})\Bin\", GenerateSafePropertyName(project, "AspNetPhysicalPath"));

// This is a bit of a hack. We're actually calling the "Copy" task on all of
Expand Down Expand Up @@ -451,15 +452,61 @@ private static void AddTasksToCopyAllDependenciesIntoBinDir(
rarTask.SetParameter("FindSerializationAssemblies", "true");
rarTask.SetParameter("FindRelatedFiles", "true");
rarTask.SetParameter("TargetFrameworkMoniker", project.TargetFrameworkMoniker);

if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave18_7))
{
// Parse the target framework version to determine if we should pass it to RAR.
// Only pass TargetFrameworkVersion for .NET Framework 4.7.1+ which has netstandard 2.0 support.
// For older frameworks, omitting this preserves the existing warning behavior (MSB3268)
// when netstandard dependencies cannot be resolved.
try
{
var frameworkName = new FrameworkName(project.TargetFrameworkMoniker);
var minVersionForNetstandard = new Version(4, 7, 1);

if (frameworkName.Version >= minVersionForNetstandard)
{
// Pass TargetFrameworkVersion so RAR can find netstandard facades
rarTask.SetParameter("TargetFrameworkVersion", $"v{frameworkName.Version}");
// Pass web.config as AppConfigFile so RAR can detect assembly binding redirects
rarTask.SetParameter("AppConfigFile", "$(WebConfigFileName)");
}
}
catch (ArgumentException)
{
// If the TargetFrameworkMoniker is malformed, skip setting TargetFrameworkVersion/AppConfigFile.
// This preserves existing behavior while avoiding an unhandled exception.
}
}

rarTask.AddOutputItem("CopyLocalFiles", copyLocalFilesItemName, null);

if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave18_7))
{
// Capture whether RAR detected a dependency on netstandard
rarTask.AddOutputProperty("DependsOnNETStandard", dependsOnNetStandardPropertyName, null);
}

// Copy all the copy-local files (reported by RAR) to the web project's "bin"
// directory.
ProjectTaskInstance copyTask = target.AddTask("Copy", conditionDescribingValidConfigurations, null);
copyTask.SetParameter("SourceFiles", "@(" + copyLocalFilesItemName + ")");
copyTask.SetParameter("SkipUnchangedFiles", "true");
copyTask.SetParameter(
"DestinationFiles",
String.Format(CultureInfo.InvariantCulture, @"@({0}->'{1}%(DestinationSubDirectory)%(Filename)%(Extension)')", copyLocalFilesItemName, destinationFolder));

if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave18_7))
{
// If any references depend on netstandard, copy netstandard.dll from the Facades folder.
// .NET Framework 4.7.1+ has netstandard 2.0 support in the Facades folder.
string netstandardFacadePath = String.Format(CultureInfo.InvariantCulture, @"$({0})Facades\netstandard.dll", targetFrameworkDirectoriesName);
string copyFacadesCondition = String.Format(CultureInfo.InvariantCulture, "'$({0})' == 'true' AND Exists('{1}')", dependsOnNetStandardPropertyName, netstandardFacadePath);
ProjectTaskInstance copyFacadesTask = target.AddTask("Copy", copyFacadesCondition, null);
copyFacadesTask.SetParameter("SourceFiles", netstandardFacadePath);
copyFacadesTask.SetParameter("SkipUnchangedFiles", "true");
copyFacadesTask.SetParameter("DestinationFolder", destinationFolder);
}
}

/// <summary>
Expand Down Expand Up @@ -1242,6 +1289,16 @@ private ProjectInstance CreateMetaproject(ProjectInstance traversalProject, Proj
"AspNetCompiler.UnsupportedMSBuildVersion",
project.ProjectName);
#else
// Set WebConfigFileName property if web.config exists (for RAR AppConfigFile parameter)
if (ChangeWaves.AreFeaturesEnabled(ChangeWaves.Wave18_7))
{
string webConfigPath = Path.Combine(project.AbsolutePath, "web.config");
if (File.Exists(webConfigPath))
{
metaprojectInstance.SetProperty("WebConfigFileName", webConfigPath);
}
}

AddMetaprojectTargetForWebProject(traversalProject, metaprojectInstance, project, null);
AddMetaprojectTargetForWebProject(traversalProject, metaprojectInstance, project, "Clean");
AddMetaprojectTargetForWebProject(traversalProject, metaprojectInstance, project, "Rebuild");
Expand Down
3 changes: 2 additions & 1 deletion src/Framework/ChangeWaves.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ internal static class ChangeWaves
internal static readonly Version Wave18_4 = new Version(18, 4);
internal static readonly Version Wave18_5 = new Version(18, 5);
internal static readonly Version Wave18_6 = new Version(18, 6);
internal static readonly Version[] AllWaves = [Wave17_10, Wave17_12, Wave17_14, Wave18_3, Wave18_4, Wave18_5, Wave18_6];
internal static readonly Version Wave18_7 = new Version(18, 7);
internal static readonly Version[] AllWaves = [Wave17_10, Wave17_12, Wave17_14, Wave18_3, Wave18_4, Wave18_5, Wave18_6, Wave18_7];

/// <summary>
/// Special value indicating that all features behind all Change Waves should be enabled.
Expand Down
Loading