diff --git a/src/Build.UnitTests/BackEnd/AssemblyLoadContextTestTasks.cs b/src/Build.UnitTests/BackEnd/AssemblyLoadContextTestTasks.cs
index b11055c16c5..be9dcb0b600 100644
--- a/src/Build.UnitTests/BackEnd/AssemblyLoadContextTestTasks.cs
+++ b/src/Build.UnitTests/BackEnd/AssemblyLoadContextTestTasks.cs
@@ -3,11 +3,69 @@
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
+using System;
+using System.Reflection;
#nullable disable
namespace AssemblyLoadContextTest
{
+ ///
+ /// Task that validates assembly version roll-forward behavior.
+ /// Tests that MSBuildLoadContext accepts newer assembly versions when older versions are requested.
+ ///
+ public class ValidateAssemblyVersionRollForward : Task
+ {
+ ///
+ /// The name of the assembly to check (e.g., "System.Collections.Immutable")
+ ///
+ [Required]
+ public string AssemblyName { get; set; }
+
+ ///
+ /// The minimum expected version (e.g., "1.0.0.0")
+ ///
+ [Required]
+ public string MinimumVersion { get; set; }
+
+ public override bool Execute()
+ {
+ try
+ {
+ // Try to load the assembly by name with minimum version
+ var minimumVersion = Version.Parse(MinimumVersion);
+ var assemblyName = new AssemblyName(AssemblyName)
+ {
+ Version = minimumVersion
+ };
+
+ // This will trigger MSBuildLoadContext.Load which should accept newer versions
+ var assembly = Assembly.Load(assemblyName);
+ var loadedVersion = assembly.GetName().Version;
+
+ Log.LogMessage(MessageImportance.High,
+ $"Requested {AssemblyName} version {minimumVersion}, loaded version {loadedVersion}");
+
+ // Verify that we got a version >= minimum
+ if (loadedVersion < minimumVersion)
+ {
+ Log.LogError(
+ $"Assembly version roll-forward failed: requested {minimumVersion}, but loaded {loadedVersion} which is older");
+ return false;
+ }
+
+ Log.LogMessage(MessageImportance.High,
+ $"Assembly version roll-forward succeeded: loaded version {loadedVersion} >= requested {minimumVersion}");
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Log.LogErrorFromException(ex, showStackTrace: true);
+ return false;
+ }
+ }
+ }
+
public class RegisterObject : Task
{
internal const string CacheKey = "RegressionForMSBuild#5080";
diff --git a/src/Build.UnitTests/BackEnd/TaskBuilder_Tests.cs b/src/Build.UnitTests/BackEnd/TaskBuilder_Tests.cs
index 9bec89727fe..7d80283306d 100644
--- a/src/Build.UnitTests/BackEnd/TaskBuilder_Tests.cs
+++ b/src/Build.UnitTests/BackEnd/TaskBuilder_Tests.cs
@@ -662,6 +662,33 @@ public void SameAssemblyFromDifferentRelativePathsSharesAssemblyLoadContext()
logger.AssertLogDoesntContain("MSB4018");
}
+#if FEATURE_ASSEMBLYLOADCONTEXT
+ ///
+ /// Regression test for https://github.com/dotnet/msbuild/issues/12370
+ /// Verifies that MSBuildLoadContext accepts newer assembly versions when older versions are requested (version roll-forward).
+ ///
+ [Fact]
+ public void MSBuildLoadContext_AcceptsNewerAssemblyVersions()
+ {
+ string realTaskPath = Assembly.GetExecutingAssembly().Location;
+
+ // Use System.Collections.Immutable as test assembly - it's available in modern .NET runtime
+ // Request an older version (1.0.0.0) which should roll forward to whatever version is available
+ string projectContents = @"
+
+
+
+
+
+";
+
+ MockLogger logger = ObjectModelHelpers.BuildProjectExpectSuccess(projectContents, _testOutput);
+
+ // Verify that the task logged success message
+ logger.AssertLogContains("Assembly version roll-forward succeeded");
+ }
+#endif
+
#if FEATURE_CODETASKFACTORY
///
diff --git a/src/Shared/MSBuildLoadContext.cs b/src/Shared/MSBuildLoadContext.cs
index 6e322309312..3e797529682 100644
--- a/src/Shared/MSBuildLoadContext.cs
+++ b/src/Shared/MSBuildLoadContext.cs
@@ -83,7 +83,7 @@ public MSBuildLoadContext(string assemblyPath)
}
AssemblyName candidateAssemblyName = AssemblyLoadContext.GetAssemblyName(candidatePath);
- if (candidateAssemblyName.Version != assemblyName.Version)
+ if (candidateAssemblyName.Version < assemblyName.Version)
{
continue;
}