| File: ApplicationModel\ProjectLaunchArgsOverrideAnnotation.cs | Web Access |
| Project: src\src\Aspire.Hosting\Aspire.Hosting.csproj (Aspire.Hosting) |
// 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; using System.Diagnostics.CodeAnalysis; namespace Aspire.Hosting.ApplicationModel; /// <summary> /// Represents an annotation that overrides the default project launch arguments /// generated by DCP for a <see cref="ProjectResource"/>. /// </summary> /// <remarks> /// <para> /// When this annotation is present on a <see cref="ProjectResource"/>, DCP will use the provided /// arguments as the base command (e.g., <c>build /t:Run</c>) instead of the default <c>run</c> verb. /// DCP still appends the project path positionally and appends <c>--configuration</c> automatically; /// only the verb and its options are overridden. This annotation is intended for verbs like /// <c>build</c> that accept the project path as a positional argument. The <c>--no-launch-profile</c> /// flag is omitted when this annotation is present. /// </para> /// <para> /// A non-empty launch-tool argument callback replaces this base command. If the callback resolves no /// arguments, this override remains the Process command. /// </para> /// </remarks> /// <example> /// Override DCP's default launch to use <c>dotnet build /t:Run</c>: /// <code> /// builder.WithAnnotation(new ProjectLaunchArgsOverrideAnnotation(["build", "/t:Run"])); /// </code> /// </example> /// <param name="arguments">The custom launch arguments to use instead of the default project launch arguments.</param> /// <param name="leadingResourceArgumentToRemove">The optional first resource argument to omit from the final launch arguments when it is already represented by <paramref name="arguments"/>.</param> [Experimental("ASPIREPROJECTS001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")] [DebuggerDisplay("Type = {GetType().Name,nq}, Arguments = {string.Join(\" \", Arguments)}")] public sealed class ProjectLaunchArgsOverrideAnnotation(IReadOnlyList<string> arguments, string? leadingResourceArgumentToRemove = null) : IResourceAnnotation { /// <summary> /// Gets the custom launch arguments to use instead of the default project args. /// </summary> public IReadOnlyList<string> Arguments { get; } = ValidateArguments(arguments).ToArray(); /// <summary> /// Gets the optional first resource argument to omit from the final launch arguments when it is already represented by <see cref="Arguments"/>. /// </summary> public string? LeadingResourceArgumentToRemove { get; } = ValidateLeadingResourceArgumentToRemove(leadingResourceArgumentToRemove); internal void Apply(IList<string> projectArgs, string projectPath, string? configuration) { projectArgs.AddRange(Arguments); projectArgs.Add(projectPath); if (!string.IsNullOrEmpty(configuration)) { projectArgs.AddRange(["--configuration", configuration]); } } private static IReadOnlyList<string> ValidateArguments(IReadOnlyList<string> arguments) { ArgumentNullException.ThrowIfNull(arguments); if (arguments.Count == 0) { throw new ArgumentException("Launch arguments must contain at least one entry.", nameof(arguments)); } return arguments; } private static string? ValidateLeadingResourceArgumentToRemove(string? leadingResourceArgumentToRemove) { if (leadingResourceArgumentToRemove is not null && leadingResourceArgumentToRemove.Length == 0) { throw new ArgumentException("The leading resource argument to remove cannot be empty.", nameof(leadingResourceArgumentToRemove)); } return leadingResourceArgumentToRemove; } }