Skip to content

[Breaking change]: Environment.GetCommandLineArgs()[0] preserves the executable invocation name #56357

Closed

Description

@jkotas

Description

Starting in .NET 11, Environment.GetCommandLineArgs()[0] preserves the name or path used to invoke an application when it is launched through its apphost executable.

Previously, the first element of the array contained the managed assembly path or, for single-file applications, the resolved executable path. As a result, it did not necessarily reflect how the application was invoked, particularly when the executable was launched through a symbolic link.

With the new behavior, Environment.GetCommandLineArgs()[0] reflects the original invocation name, including relative paths and symbolic link names, rather than a resolved path.

Applications launched using dotnet <application.dll> retain their existing behavior.

Version

.NET 11 Preview 7

Previous behavior

When an application was launched through its apphost executable, Environment.GetCommandLineArgs()[0] returned the managed assembly path or, for single-file applications, the resolved executable path.

For example, consider an application named foo and a symbolic link named special_myapp pointing to its executable:

ln -s foo special_myapp
./special_myapp 1 2 3

Previously, Environment.GetCommandLineArgs()[0] did not preserve ./special_myapp. Instead, it returned the fully resolved managed assembly path (myapp.dll) or the resolved executable path (myapp), depending on the deployment model.

New behavior

When an application is launched through its apphost executable, Environment.GetCommandLineArgs()[0] preserves the original executable invocation name.

For example, ./special_myapp 1 2 3 from the example above now returns ./special_myapp.

Type of breaking change

  • Binary incompatible: Existing binaries might encounter a breaking change in behavior, such as failure to load or execute, and if so, require recompilation.
  • Source incompatible: When recompiled using the new SDK or component or to target the new runtime, existing source code might require source changes to compile successfully.
  • Behavioral change: Existing binaries might behave differently at run time.

Reason for change

Previously, Environment.GetCommandLineArgs()[0] did not consistently reflect how an application was invoked. In particular, applications launched through symbolic links could not use this API to determine the invocation name.

The new behavior aligns more closely with the native process argument convention, where argv[0] represents the invocation name supplied to the process.

This change enables applications to distinguish between different invocation names, including symbolic links.

Recommended action

If your application relies on Environment.GetCommandLineArgs()[0] to retrieve the managed assembly path or resolved executable path, review the code to determine whether the new behavior affects it.

Depending on your requirements:

Use Environment.ProcessPath to retrieve the path to the executable associated with the current process.

Use Assembly.GetEntryAssembly()?.Location when you need the managed entry assembly location. Note that this property returns an empty string for bundled assemblies in single-file applications.

Continue using Environment.GetCommandLineArgs()[0] when you need the original executable invocation name.

Feature area

Core .NET libraries

Affected APIs

System.Environment.GetCommandLineArgs()

Metadata

Metadata

Labels

breaking-changeIndicates a .NET Core breaking change

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions