Runtime: single file publish: AppContext.BaseDirectory doesn't point to apphost directory

Created on 29 Jul 2019  路  11Comments  路  Source: dotnet/runtime

Steps to reproduce

  1. Create a hello world program:
    ```c#
    static void Main(string[] args)
    {
    Console.WriteLine("Hello World!");
    Console.WriteLine($"Base Directory: {AppContext.BaseDirectory}");
    Console.WriteLine($"Assembly Location: {typeof(Program).Assembly.Location}");
    }
2. Publish self contained - `dotnet publish -c Release -r win-x64 -p:PublishSingleFile=True --self-contained false` (or self-contained)

3. Run the resulting exe file.

## Expected  behavior

According to the [design document](https://github.com/dotnet/designs/blob/686205657ace53b3e6d568cb098be302f6974956/accepted/single-file/design.md), `AppContext.BaseDirectory` is the API that developers should use to access the path where the app host resides.

The app context base directory should therefore not be in `AppData\Local\Temp\.net\`.

Background: I want to use this directory to load override config files.

## Actual behavior

C:\demos\testcons\bin\Releasenetcoreapp3.0\win-x64\publish>testcons.exe
Hello World!
Base Directory: C:\Users\ullrimar\AppData\Local\Temp.net\testcons\53kpwgv0.3mq\
Assembly Location: C:\Users\ullrimar\AppData\Local\Temp.net\testcons\53kpwgv0.3mq\testcons.dll

## Environment data

dotnet --info
.NET Core SDK (reflecting any global.json):
Version: 3.0.100-preview7-012821
Commit: 6348f1068a

Runtime Environment:
OS Name: Windows
OS Version: 10.0.18362
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\3.0.100-preview7-012821\

Host (useful for support):
Version: 3.0.0-preview7-27912-14
Commit: 4da6ee6450
```

cc @vitek-karas

area-Single-File

Most helpful comment

Can make AppContext.BaseDirectory an independent way for getting run root?
If using Process.GetCurrentProcess().MainModule.FileName, it works fine with single file app, but when run in vs test, the value returned is 'dotnet.exe'.

All 11 comments

@swaroop-sridhar is there any other path at the moment that points to the app host directory and/or name?

In the current version, we simply extract the contents of the bundle to a directory on the disk, and declare that directory as the base-directory. This choice aims to preserve compatibility for apps that assume that apcontext.basedirectory contains the app.dll. In the current version, we'll need to use native APIs such as GetModuleFileName to get the path of the native AppHost.

In subsequent versions, once the app.dll is processed directly from the bundle, the design doc discusses options to set AppContext.BaseDirectory. The current proposal is to set it to the location of the AppHost.

You could also try using: Process.GetCurrentProcess().MainModule.FileName as suggested here: https://github.com/dotnet/coreclr/issues/20287#issuecomment-506590901

That works, thanks!

Is this (esp. AppContext.BaseDirectory) subject to change? If not, I'd ask for the design document to be in line with the actual implementation, or hint at which parts are part of .NET Core 3.0.

Yes @dasMulli the value of AppContext.BaseDirectory is open question in the next version of .net core, -- because when we load assemblies directly from the bundle, there's no extraction directory. My current thinking is that it will point to the host directory, as indicated in the design doc.

Can make AppContext.BaseDirectory an independent way for getting run root?
If using Process.GetCurrentProcess().MainModule.FileName, it works fine with single file app, but when run in vs test, the value returned is 'dotnet.exe'.

FYI seems like starting with .NET SDK 3.1.201, the Diagnostics.Process.GetCurrentProcess().MainModule.FileName changed behaviour with regards to non-single file publish.

with .NET SDK 3.1.101:
I could use Diagnostics.Process.GetCurrentProcess().MainModule.FileName for both single-file publish, and debug development (dotnet watch run) and it returned the base directory in both cases, but

in .NET SDK 3.1.201:
In debug development mode (dotnet watch run), Diagnostics.Process.GetCurrentProcess().MainModule.FileName returns the dotnet executable (e.g. /usr/local/share/dotnet/dotnet) so I had to amend my code to following:

  let baseDir =
#if DEBUG
    AppContext.BaseDirectory
#else
    Diagnostics.Process.GetCurrentProcess().MainModule.FileName
    |> IO.Path.GetDirectoryName
#endif

@theimowski are you running this on macOS?

In order to comply with notarization requirements, the signed binary (/usr/local/share/dotnet/dotnet) is used so users don't get too many errors.

You can get the old behavior again by specifying this in your project file:

<PropertyGroup>
  <UseAppHost>true</UseAppHost>
</PropertyGroup>

See https://docs.microsoft.com/en-us/dotnet/core/install/macos-notarization-issues for more details

Thanks @dasMulli yup I'm running on macOS and missed the notarization update. The UseAppHost property did the job for me 馃憤

Tagging subscribers to this area: @swaroop-sridhar
Notify danmosemsft if you want to be subscribed.

This issue is fixed in .net5

Was this page helpful?
0 / 5 - 0 ratings

Related issues

omajid picture omajid  路  3Comments

aggieben picture aggieben  路  3Comments

chunseoklee picture chunseoklee  路  3Comments

Timovzl picture Timovzl  路  3Comments

jchannon picture jchannon  路  3Comments