diff --git a/src/Aspire.Cli/DotNet/DotNetSdkInstaller.cs b/src/Aspire.Cli/DotNet/DotNetSdkInstaller.cs
index 99b65f04b4a..9ed276e5bfe 100644
--- a/src/Aspire.Cli/DotNet/DotNetSdkInstaller.cs
+++ b/src/Aspire.Cli/DotNet/DotNetSdkInstaller.cs
@@ -90,7 +90,7 @@ internal sealed class DotNetSdkInstaller(IFeatures features, IConfiguration conf
}
// Check if this version meets the minimum requirement
- if (SemVersion.ComparePrecedence(sdkVersion, minVersion) >= 0)
+ if (MeetsMinimumRequirement(sdkVersion, minVersion, minimumVersion))
{
meetsMinimum = true;
}
@@ -152,4 +152,25 @@ public string GetEffectiveMinimumSdkVersion()
return MinimumSdkVersion;
}
}
+
+ ///
+ /// Checks if an installed SDK version meets the minimum requirement.
+ /// For .NET 10.x requirements, allows any .NET 10.x version including prereleases.
+ ///
+ /// The installed SDK version.
+ /// The required minimum version (parsed).
+ /// The required version string.
+ /// True if the installed version meets the requirement.
+ private static bool MeetsMinimumRequirement(SemVersion installedVersion, SemVersion requiredVersion, string requiredVersionString)
+ {
+ // Special handling for .NET 10.0.100 requirement - allow any .NET 10.x version
+ if (requiredVersionString == MinimumSdkVersionSingleFileAppHost)
+ {
+ // If we require 10.0.100, accept any version that is >= 10.0.0
+ return installedVersion.Major >= 10;
+ }
+
+ // For all other requirements, use strict version comparison
+ return SemVersion.ComparePrecedence(installedVersion, requiredVersion) >= 0;
+ }
}
\ No newline at end of file
diff --git a/tests/Aspire.Cli.Tests/DotNetSdkInstallerTests.cs b/tests/Aspire.Cli.Tests/DotNetSdkInstallerTests.cs
index c33f5a61d15..bc7211d699b 100644
--- a/tests/Aspire.Cli.Tests/DotNetSdkInstallerTests.cs
+++ b/tests/Aspire.Cli.Tests/DotNetSdkInstallerTests.cs
@@ -6,6 +6,7 @@
using Aspire.Cli.DotNet;
using Aspire.Cli.Resources;
using Microsoft.Extensions.Configuration;
+using Semver;
namespace Aspire.Cli.Tests;
@@ -238,6 +239,70 @@ public void ErrorMessage_Format_IsCorrect()
Assert.Equal("The Aspire CLI requires .NET SDK version 9.0.302 or later. Detected: (not found).", message);
}
+ [Fact]
+ public void MeetsMinimumRequirement_AllowsDotNet10Prereleases_ForSingleFileAppHost()
+ {
+ // Test the logic we added for allowing .NET 10 prereleases
+ var installedVersion = SemVersion.Parse("10.0.100-preview.1.25463.5", SemVersionStyles.Strict);
+ var requiredVersion = SemVersion.Parse("10.0.100", SemVersionStyles.Strict);
+ var requiredVersionString = "10.0.100";
+
+ // Use reflection to access the private method
+ var method = typeof(DotNetSdkInstaller).GetMethod("MeetsMinimumRequirement",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
+ var result = (bool)method!.Invoke(null, new object[] { installedVersion, requiredVersion, requiredVersionString })!;
+
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void MeetsMinimumRequirement_AllowsDotNet10LatestPrerelease_ForSingleFileAppHost()
+ {
+ // Test with a more recent .NET 10 prerelease
+ var installedVersion = SemVersion.Parse("10.1.0-preview.2.25999.99", SemVersionStyles.Strict);
+ var requiredVersion = SemVersion.Parse("10.0.100", SemVersionStyles.Strict);
+ var requiredVersionString = "10.0.100";
+
+ // Use reflection to access the private method
+ var method = typeof(DotNetSdkInstaller).GetMethod("MeetsMinimumRequirement",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
+ var result = (bool)method!.Invoke(null, new object[] { installedVersion, requiredVersion, requiredVersionString })!;
+
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void MeetsMinimumRequirement_RejectsDotNet9_ForSingleFileAppHost()
+ {
+ // Test that .NET 9 is still rejected for single file apphost requirements
+ var installedVersion = SemVersion.Parse("9.0.999", SemVersionStyles.Strict);
+ var requiredVersion = SemVersion.Parse("10.0.100", SemVersionStyles.Strict);
+ var requiredVersionString = "10.0.100";
+
+ // Use reflection to access the private method
+ var method = typeof(DotNetSdkInstaller).GetMethod("MeetsMinimumRequirement",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
+ var result = (bool)method!.Invoke(null, new object[] { installedVersion, requiredVersion, requiredVersionString })!;
+
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void MeetsMinimumRequirement_UsesStrictComparison_ForNonSingleFileAppHost()
+ {
+ // Test that other version requirements still use strict comparison
+ var installedVersion = SemVersion.Parse("9.0.301", SemVersionStyles.Strict);
+ var requiredVersion = SemVersion.Parse("9.0.302", SemVersionStyles.Strict);
+ var requiredVersionString = "9.0.302";
+
+ // Use reflection to access the private method
+ var method = typeof(DotNetSdkInstaller).GetMethod("MeetsMinimumRequirement",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
+ var result = (bool)method!.Invoke(null, new object[] { installedVersion, requiredVersion, requiredVersionString })!;
+
+ Assert.False(result);
+ }
+
private static IConfiguration CreateEmptyConfiguration()
{
return new ConfigurationBuilder().Build();