@@ -966,31 +966,31 @@ private async Task CreateExecutableAsync(AppResource er, ILogger resourceLogger,
966966 }
967967 var spec = exe . Spec ;
968968
969+ // Don't create an args collection unless needed. A null args collection means a project run by the will use args provided by the launch profile.
970+ // https://github.com/dotnet/aspire/blob/main/docs/specs/IDE-execution.md#launch-profile-processing-project-launch-configuration
971+ spec . Args = null ;
972+
969973 // An executable can be restarted so args must be reset to an empty state.
970974 // After resetting, first apply any dotnet project related args, e.g. configuration, and then add args from the model resource.
971- spec . Args = [ ] ;
972- if ( er . DcpResource . TryGetAnnotationAsObjectList < string > ( CustomResource . ResourceProjectArgsAnnotation , out var projectArgs ) )
975+ if ( er . DcpResource . TryGetAnnotationAsObjectList < string > ( CustomResource . ResourceProjectArgsAnnotation , out var projectArgs ) && projectArgs . Count > 0 )
973976 {
977+ spec . Args ??= [ ] ;
974978 spec . Args . AddRange ( projectArgs ) ;
975979 }
976980
977- var launchArgs = new List < ( string Value , bool IsSensitive , bool AnnotationOnly ) > ( ) ;
981+ // Get args from app host model resource.
982+ ( var appHostArgs , var failedToApplyArgs ) = await BuildArgsAsync ( resourceLogger , er . ModelResource , cancellationToken ) . ConfigureAwait ( false ) ;
978983
979- // If the executable is a project then include any command line args from the launch profile.
980- if ( er . ModelResource is ProjectResource project )
981- {
982- // When the .NET project is launched from an IDE the launch profile args are automatically added.
983- // We still want to display the args in the dashboard so only add them to the custom arg annotations.
984- var annotationOnly = spec . ExecutionType == ExecutionType . IDE ;
984+ var launchArgs = BuildLaunchArgs ( er , spec , appHostArgs ) ;
985985
986- var launchProfileArgs = GetLaunchProfileArgs ( project . GetEffectiveLaunchProfile ( ) ? . LaunchProfile ) ;
987- launchArgs . AddRange ( launchProfileArgs . Select ( a => ( a , isSensitive : false , annotationOnly ) ) ) ;
986+ var executableArgs = launchArgs . Where ( a => ! a . AnnotationOnly ) . Select ( a => a . Value ) . ToList ( ) ;
987+ if ( executableArgs . Count > 0 )
988+ {
989+ spec . Args ??= [ ] ;
990+ spec . Args . AddRange ( executableArgs ) ;
988991 }
989992
990- ( var args , var failedToApplyArgs ) = await BuildArgsAsync ( resourceLogger , er . ModelResource , cancellationToken ) . ConfigureAwait ( false ) ;
991- launchArgs . AddRange ( args . Select ( a => ( a . Value , a . IsSensitive , annotationOnly : false ) ) ) ;
992-
993- spec . Args . AddRange ( launchArgs . Where ( a => ! a . AnnotationOnly ) . Select ( a => a . Value ) ) ;
993+ // Arg annotations are what is displayed in the dashboard.
994994 er . DcpResource . SetAnnotationAsObjectList ( CustomResource . ResourceAppArgsAnnotation , launchArgs . Select ( a => new AppLaunchArgumentAnnotation ( a . Value , isSensitive : a . IsSensitive ) ) ) ;
995995
996996 ( spec . Env , var failedToApplyConfiguration ) = await BuildEnvVarsAsync ( resourceLogger , er . ModelResource , cancellationToken ) . ConfigureAwait ( false ) ;
@@ -1003,6 +1003,37 @@ private async Task CreateExecutableAsync(AppResource er, ILogger resourceLogger,
10031003 await _kubernetesService . CreateAsync ( exe , cancellationToken ) . ConfigureAwait ( false ) ;
10041004 }
10051005
1006+ private static List < ( string Value , bool IsSensitive , bool AnnotationOnly ) > BuildLaunchArgs ( AppResource er , ExecutableSpec spec , List < ( string Value , bool IsSensitive ) > appHostArgs )
1007+ {
1008+ // Launch args is the final list of args that are displayed in the UI and possibly added to the executable spec.
1009+ // They're built from app host resource model args and any args in the effective launch profile.
1010+ // Follows behavior in the IDE execution spec when in IDE execution mode:
1011+ // https://github.com/dotnet/aspire/blob/main/docs/specs/IDE-execution.md#launch-profile-processing-project-launch-configuration
1012+ var launchArgs = new List < ( string Value , bool IsSensitive , bool AnnotationOnly ) > ( ) ;
1013+
1014+ // If the executable is a project then include any command line args from the launch profile.
1015+ if ( er . ModelResource is ProjectResource project )
1016+ {
1017+ // Args in the launch profile is used when:
1018+ // 1. The project is run as an executable. Launch profile args are combined with app host supplied args.
1019+ // 2. The project is run by the IDE and no app host args are specified.
1020+ if ( spec . ExecutionType == ExecutionType . Process || ( spec . ExecutionType == ExecutionType . IDE && appHostArgs . Count == 0 ) )
1021+ {
1022+ // When the .NET project is launched from an IDE the launch profile args are automatically added.
1023+ // We still want to display the args in the dashboard so only add them to the custom arg annotations.
1024+ var annotationOnly = spec . ExecutionType == ExecutionType . IDE ;
1025+
1026+ var launchProfileArgs = GetLaunchProfileArgs ( project . GetEffectiveLaunchProfile ( ) ? . LaunchProfile ) ;
1027+ launchArgs . AddRange ( launchProfileArgs . Select ( a => ( a , isSensitive : false , annotationOnly ) ) ) ;
1028+ }
1029+ }
1030+
1031+ // In the situation where args are combined (process execution) the app host args are added after the launch profile args.
1032+ launchArgs . AddRange ( appHostArgs . Select ( a => ( a . Value , a . IsSensitive , annotationOnly : false ) ) ) ;
1033+
1034+ return launchArgs ;
1035+ }
1036+
10061037 private static List < string > GetLaunchProfileArgs ( LaunchProfile ? launchProfile )
10071038 {
10081039 var args = new List < string > ( ) ;
0 commit comments