sxagan
sxagan

Reputation: 188

Cannot get original executable path for .NET Core 3.0 single file '/p:PublishSingleFile=true'

I published a .NET Core console app with '/p:PublishSingleFile=true' option, but now assembly path is the temporary path where it inflated to.

Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)

now returns:

C:\Users\DEFUSER\AppData\Local\Temp\.net\myApp\3dzfa4fp.353\_myApp.json

originally:

C:\devel\myApp\bin\publish\_myApp.json

How can I get the original path of where i put the exe file originally?

thanks in advance!

Upvotes: 11

Views: 4001

Answers (3)

Guru Stron
Guru Stron

Reputation: 141565

Docs for single-file deployment and executable mention that some Assembly APIs will not work in this mode, including Location, which will return an empty string:

API Note
Assembly.CodeBase Throws System.PlatformNotSupportedException.
Assembly.EscapedCodeBase Throws System.PlatformNotSupportedException.
Assembly.GetFile Throws System.IO.IOException.
Assembly.GetFiles Throws System.IO.IOException.
Assembly.Location Returns an empty string.
AssemblyName.CodeBase Returns null.
AssemblyName.EscapedCodeBase Returns null.
Module.FullyQualifiedName Returns a string with the value of <Unknown> or throws an exception.
Marshal.GetHINSTANCE Returns -1.
Module.Name Returns a string with the value of <Unknown>.

There are some workarounds mentioned:

  • To access files next to the executable, use System.AppContext.BaseDirectory

  • To find the file name of the executable, use the first element of System.Environment.GetCommandLineArgs, or starting with .NET 6, use the file name from System.Environment.ProcessPath.

So based on this you can use Environment.ProcessPath (since .NET 6) or Environment.GetCommandLineArgs()[0] (since .NET 5, can be preferable in cases when the executable is distributed and run in different ways, i.e. via single file, .exe or via dotnet command).

From Environment.GetCommandLineArgs remarks:

The first element in the array contains the file name of the executing program. If the file name is not available, the first element is equal to String.Empty. The remaining elements contain any additional tokens entered on the command line.

In .NET 5 and later versions, for single-file publishing, the first element is the name of the host executable.

Upvotes: 6

Pavel Anikhouski
Pavel Anikhouski

Reputation: 23208

There is a new .NET 6.0 property Environment.ProcessPath added exactly for that reason

Returns the path of the executable that started the currently executing process

Design notes can be found here

Upvotes: 7

Grzegorz Smulko
Grzegorz Smulko

Reputation: 2803

Based on https://github.com/dotnet/coreclr/issues/25623, which was also confirmed by Scott Hanselman a year later:

  • .NET Core: Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)
  • .NET 5: AppContext.BaseDirectory.

Upvotes: 23

Related Questions