From b83130319dedf1539131b9cb54bddcf42096ae58 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Fri, 25 Sep 2026 14:33:06 -0500 Subject: [PATCH 1/2] Remove Experimental attributes from Aspire.Hosting.Dotnet Keep the package prerelease while removing redundant experimental API diagnostics. Update public API coverage and documentation, and remove obsolete suppressions within the integration and its tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../DotnetProjectBuildCoordinator.cs | 2 +- .../DotnetProjectHostingExtensions.cs | 12 -------- .../DotnetProjectResource.cs | 2 -- src/Aspire.Hosting.Dotnet/README.md | 2 +- .../DotnetProjectBuildCoordinatorTests.cs | 2 +- .../DotnetProjectBuildEnvironmentTests.cs | 2 +- .../DotnetProjectOptionsTests.cs | 1 - .../DotnetProjectPublicApiTests.cs | 28 ++++++------------- .../DotnetProjectResourceTests.cs | 1 - 9 files changed, 12 insertions(+), 40 deletions(-) diff --git a/src/Aspire.Hosting.Dotnet/DotnetProjectBuildCoordinator.cs b/src/Aspire.Hosting.Dotnet/DotnetProjectBuildCoordinator.cs index aeb00f0bdac..edd759f25f1 100644 --- a/src/Aspire.Hosting.Dotnet/DotnetProjectBuildCoordinator.cs +++ b/src/Aspire.Hosting.Dotnet/DotnetProjectBuildCoordinator.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#pragma warning disable ASPIREDOTNETPROJECT001, ASPIREEXTENSION001, ASPIREPIPELINES001, ASPIREPROJECTS001 +#pragma warning disable ASPIREEXTENSION001, ASPIREPIPELINES001, ASPIREPROJECTS001 using System.Globalization; using System.Runtime.CompilerServices; diff --git a/src/Aspire.Hosting.Dotnet/DotnetProjectHostingExtensions.cs b/src/Aspire.Hosting.Dotnet/DotnetProjectHostingExtensions.cs index 2dacc9caa25..69a69de707a 100644 --- a/src/Aspire.Hosting.Dotnet/DotnetProjectHostingExtensions.cs +++ b/src/Aspire.Hosting.Dotnet/DotnetProjectHostingExtensions.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using System.Reflection; using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Dotnet; @@ -65,7 +64,6 @@ public static class DotnetProjectHostingExtensions /// .WithBuildEnvironment("BUILD_FLAVOR", "custom"); /// /// - [Experimental("ASPIREDOTNETPROJECT001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] [AspireExport] public static IResourceBuilder WithBuildEnvironment( this IResourceBuilder builder, @@ -107,7 +105,6 @@ public static IResourceBuilder WithBuildEnvironment( /// temporary MSBuild response files, and the values can appear in build diagnostics. /// /// - [Experimental("ASPIREDOTNETPROJECT001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] [AspireExportIgnore(Reason = "Raw Action delegate callbacks are not ATS-compatible.")] public static IResourceBuilder WithBuildEnvironment( this IResourceBuilder builder, @@ -151,7 +148,6 @@ public static IResourceBuilder WithBuildEnvironment( /// temporary MSBuild response files, and the values can appear in build diagnostics. /// /// - [Experimental("ASPIREDOTNETPROJECT001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] [AspireExportIgnore(Reason = "Raw Func delegate callbacks are not ATS-compatible.")] public static IResourceBuilder WithBuildEnvironment( this IResourceBuilder builder, @@ -181,7 +177,6 @@ internal static void ValidateBuildEnvironmentSupport(IResource resource, IProjec /// /// Configures the number of .NET project replicas for polyglot AppHosts. /// - [Experimental("ASPIREDOTNETPROJECT001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] [AspireExport("withDotnetProjectReplicas", MethodName = "withReplicas")] internal static IResourceBuilder WithReplicasForPolyglot( this IResourceBuilder builder, @@ -193,7 +188,6 @@ internal static IResourceBuilder WithReplicasForPolyglot( /// /// Disables forwarded headers for a .NET project in polyglot AppHosts. /// - [Experimental("ASPIREDOTNETPROJECT001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] [AspireExport("disableDotnetProjectForwardedHeaders", MethodName = "disableForwardedHeaders")] internal static IResourceBuilder DisableForwardedHeadersForPolyglot( this IResourceBuilder builder) @@ -204,7 +198,6 @@ internal static IResourceBuilder DisableForwardedHeadersF /// /// Configures endpoint environment-variable injection for a .NET project in polyglot AppHosts. /// - [Experimental("ASPIREDOTNETPROJECT001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] [AspireExport("withDotnetProjectEndpointsInEnvironment", MethodName = "withEndpointsInEnvironment")] internal static IResourceBuilder WithEndpointsInEnvironmentForPolyglot( this IResourceBuilder builder, @@ -244,7 +237,6 @@ internal static IResourceBuilder WithEndpointsInEnvironme /// /// /// - [Experimental("ASPIREDOTNETPROJECT001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] [AspireExportIgnore(Reason = "Polyglot AppHosts use the internal addDotnetProject dispatcher export.")] public static IResourceBuilder AddDotnetProject(this IDistributedApplicationBuilder builder, [ResourceName] string name, string path) { @@ -258,7 +250,6 @@ public static IResourceBuilder AddDotnetProject(this IDis /// /// Adds a C# application resource. /// - [Experimental("ASPIREDOTNETPROJECT001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] [AspireExport("addDotnetProject")] internal static IResourceBuilder AddDotnetProjectForPolyglot( this IDistributedApplicationBuilder builder, @@ -296,7 +287,6 @@ internal static IResourceBuilder AddDotnetProjectForPolyg /// /// /// - [Experimental("ASPIREDOTNETPROJECT001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] [AspireExportIgnore(Reason = "Polyglot AppHosts use the internal addDotnetProject dispatcher export.")] public static IResourceBuilder AddDotnetProject(this IDistributedApplicationBuilder builder, [ResourceName] string name, string path, Action configure) { @@ -468,7 +458,6 @@ List GetLaunchProfileArguments(IResource resource) return resource; } -#pragma warning disable ASPIREDOTNETPROJECT001 internal static async Task ResolveRunPropertiesAfterBuildAsync( DotnetProjectBuildCoordinator.CoordinatorState coordinator, DotnetProjectResource resource, @@ -483,7 +472,6 @@ await coordinator.WaitForBuildCompletionAsync( return await resolver(cancellationToken).ConfigureAwait(false); } -#pragma warning restore ASPIREDOTNETPROJECT001 private static void ApplyProjectResourceOptions(ProjectResourceOptions target, DotnetProjectOptions source) { diff --git a/src/Aspire.Hosting.Dotnet/DotnetProjectResource.cs b/src/Aspire.Hosting.Dotnet/DotnetProjectResource.cs index c8f4de06c17..b64958a0a47 100644 --- a/src/Aspire.Hosting.Dotnet/DotnetProjectResource.cs +++ b/src/Aspire.Hosting.Dotnet/DotnetProjectResource.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System.Diagnostics.CodeAnalysis; using Aspire.Hosting.ApplicationModel; #pragma warning disable ASPIREPROJECTS001 // ProjectLaunchDefaultsAnnotation is experimental. @@ -23,7 +22,6 @@ namespace Aspire.Hosting.Dotnet; /// explicitly configured for publishing by its builder. /// /// -[Experimental("ASPIREDOTNETPROJECT001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] [AspireExport(ExposeProperties = true)] public class DotnetProjectResource : ExecutableResource, diff --git a/src/Aspire.Hosting.Dotnet/README.md b/src/Aspire.Hosting.Dotnet/README.md index 9c7b46b8646..bd8d68ce820 100644 --- a/src/Aspire.Hosting.Dotnet/README.md +++ b/src/Aspire.Hosting.Dotnet/README.md @@ -5,7 +5,7 @@ Use this integration to model, configure, and orchestrate C# projects and file-b `Aspire.Hosting.Python`, and `Aspire.Hosting.JavaScript`. > [!NOTE] -> `AddDotnetProject` is experimental and is exposed under the `ASPIREDOTNETPROJECT001` diagnostic. +> `Aspire.Hosting.Dotnet` is a prerelease package. > Its API surface may change in future releases. ## Getting started diff --git a/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectBuildCoordinatorTests.cs b/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectBuildCoordinatorTests.cs index 68c78330d78..200ebfc2320 100644 --- a/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectBuildCoordinatorTests.cs +++ b/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectBuildCoordinatorTests.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#pragma warning disable ASPIREDOTNETPROJECT001, ASPIREEXTENSION001, ASPIREPIPELINES001, ASPIREPROJECTS001 +#pragma warning disable ASPIREEXTENSION001, ASPIREPIPELINES001, ASPIREPROJECTS001 using System.IO.Compression; using System.Reflection; diff --git a/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectBuildEnvironmentTests.cs b/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectBuildEnvironmentTests.cs index c742fa7a548..d96e7717f26 100644 --- a/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectBuildEnvironmentTests.cs +++ b/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectBuildEnvironmentTests.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#pragma warning disable ASPIREDOTNETPROJECT001, ASPIREPROJECTS001 +#pragma warning disable ASPIREPROJECTS001 using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Utils; diff --git a/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectOptionsTests.cs b/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectOptionsTests.cs index 221dc594de8..44c03f57c04 100644 --- a/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectOptionsTests.cs +++ b/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectOptionsTests.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#pragma warning disable ASPIREDOTNETPROJECT001 #pragma warning disable ASPIREEXTENSION001 using Aspire.Hosting.ApplicationModel; diff --git a/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectPublicApiTests.cs b/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectPublicApiTests.cs index 6f404e1e0c2..a88368777d9 100644 --- a/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectPublicApiTests.cs +++ b/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectPublicApiTests.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#pragma warning disable ASPIREDOTNETPROJECT001 #pragma warning disable ASPIREPROJECTS001 using System.Diagnostics.CodeAnalysis; @@ -16,12 +15,9 @@ public class DotnetProjectPublicApiTests // ---- Experimental tagging ------------------------------------------------------ [Fact] - public void DotnetProjectResourceIsTaggedWithExpectedExperimentalDiagnostic() + public void DotnetProjectResourceIsNotExperimental() { - var attribute = Assert.Single(typeof(DotnetProjectResource).GetCustomAttributes()); - - Assert.Equal("ASPIREDOTNETPROJECT001", attribute.DiagnosticId); - Assert.Equal("https://aka.ms/aspire/diagnostics/{0}", attribute.UrlFormat); + Assert.Empty(typeof(DotnetProjectResource).GetCustomAttributes()); } [Fact] @@ -32,23 +28,15 @@ public void DotnetProjectResourceImplementsPublishingContracts() } [Fact] - public void EveryPublicAddDotnetProjectOverloadIsTaggedWithExpectedExperimentalDiagnostic() + public void DotnetProjectHostingExtensionsAreNotExperimental() { - var overloads = typeof(DotnetProjectHostingExtensions) - .GetMethods(BindingFlags.Public | BindingFlags.Static) - .Where(m => m.Name == nameof(DotnetProjectHostingExtensions.AddDotnetProject)) - .ToList(); - - // Guards against silently losing coverage if an overload is added or removed. - Assert.Equal(2, overloads.Count); + Assert.Empty(typeof(DotnetProjectHostingExtensions).GetCustomAttributes()); - foreach (var method in overloads) - { - var attribute = Assert.Single(method.GetCustomAttributes()); + var methods = typeof(DotnetProjectHostingExtensions) + .GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly); - Assert.Equal("ASPIREDOTNETPROJECT001", attribute.DiagnosticId); - Assert.Equal("https://aka.ms/aspire/diagnostics/{0}", attribute.UrlFormat); - } + Assert.NotEmpty(methods); + Assert.All(methods, method => Assert.Empty(method.GetCustomAttributes())); } // ---- DotnetProjectResource constructor guards -------------------------------- diff --git a/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectResourceTests.cs b/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectResourceTests.cs index add8d7e4fd3..611f3d07794 100644 --- a/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectResourceTests.cs +++ b/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectResourceTests.cs @@ -1,7 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -#pragma warning disable ASPIREDOTNETPROJECT001 #pragma warning disable ASPIREEXTENSION001 #pragma warning disable ASPIREPERSISTENCE001 #pragma warning disable ASPIREPIPELINES001 From c943a56fd0f94c08d52bac157405a626fa3a98c8 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Fri, 25 Sep 2026 15:29:43 -0500 Subject: [PATCH 2/2] Remove unnecessary Dotnet experimental attribute tests Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../DotnetProjectPublicApiTests.cs | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectPublicApiTests.cs b/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectPublicApiTests.cs index a88368777d9..03778cc48ad 100644 --- a/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectPublicApiTests.cs +++ b/tests/Aspire.Hosting.Dotnet.Tests/DotnetProjectPublicApiTests.cs @@ -3,8 +3,6 @@ #pragma warning disable ASPIREPROJECTS001 -using System.Diagnostics.CodeAnalysis; -using System.Reflection; using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Utils; @@ -12,14 +10,6 @@ namespace Aspire.Hosting.Dotnet.Tests; public class DotnetProjectPublicApiTests { - // ---- Experimental tagging ------------------------------------------------------ - - [Fact] - public void DotnetProjectResourceIsNotExperimental() - { - Assert.Empty(typeof(DotnetProjectResource).GetCustomAttributes()); - } - [Fact] public void DotnetProjectResourceImplementsPublishingContracts() { @@ -27,18 +17,6 @@ public void DotnetProjectResourceImplementsPublishingContracts() Assert.True(typeof(IContainerFilesDestinationResource).IsAssignableFrom(typeof(DotnetProjectResource))); } - [Fact] - public void DotnetProjectHostingExtensionsAreNotExperimental() - { - Assert.Empty(typeof(DotnetProjectHostingExtensions).GetCustomAttributes()); - - var methods = typeof(DotnetProjectHostingExtensions) - .GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly); - - Assert.NotEmpty(methods); - Assert.All(methods, method => Assert.Empty(method.GetCustomAttributes())); - } - // ---- DotnetProjectResource constructor guards -------------------------------- [Theory]