🐥note.

小鳥とMicrosoft <3 なエンジニアの技術Blog📚

/p:PublishSingleFile=trueでdotnet publishしたときのパスの扱い

dotnet publish -c Release -r win10-x64 /p:PublishSingleFile=trueで単一ファイルの発行を際に自分自身(Exe)のパスの取得ではまった話です。

Single Binary化

dotnet publishする際にPublishSingleFileRuntimeIdentifierを指定することで単一のExeを出力できます。

publishコマンド 例

dotnet publish -c Release -r win10-x64 /p:PublishSingleFile=true

またはcsprojに以下の内容を記載してdotnet publish -c Releaseしても同様です。

.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.0</TargetFramework>
+    <PublishSingleFile>true</PublishSingleFile>
+    <RuntimeIdentifier>win10-x64</RuntimeIdentifier>
  </PropertyGroup>

  </Project>

単一のExeといっても実際にはBuildフォルダ内のDLLとかを圧縮して保持し、Exe実行時に解凍してるだけっぽい?

実行してみる

publishしたExeを実行すると%USERPROFILE%/AppData/Local/Temp/.net/以下にアプリケーション毎のフォルダが生成される。

試しに以下のコードのExeをPublishし、実行してみる。

Path 検証コード

using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;

namespace PublishSingleFileSample
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine($"GetCallingAssembly:\t{Path.GetDirectoryName(Assembly.GetCallingAssembly().Location)}");
            Console.WriteLine($"GetEntryAssembly:\t{Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)}");
            Console.WriteLine($"GetExecutingAssembly:\t{Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)}");
            Console.WriteLine($"GetCurrentProcess:\t{Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)}");
            Console.WriteLine($"GetCurrentDirectory:\t{Directory.GetCurrentDirectory()}");
            Console.WriteLine($"CurrentDirectory:\t{Environment.CurrentDirectory}");
        }
    }
}

実行した結果は以下の通りです。

実行結果

PS C:\Users\piyosi> .\work\PublishSingleFileSample.exe
GetCallingAssembly:     C:\Users\piyosi\AppData\Local\Temp\.net\PublishSingleFileSample\32lboto0.c0l
GetEntryAssembly:       C:\Users\piyosi\AppData\Local\Temp\.net\PublishSingleFileSample\32lboto0.c0l
GetExecutingAssembly:   C:\Users\piyosi\AppData\Local\Temp\.net\PublishSingleFileSample\32lboto0.c0l
GetCurrentProcess:      C:\Users\piyosi\work
GetCurrentDirectory:    C:\Users\piyosi
CurrentDirectory:       C:\Users\piyosi

Assembly系で取得したパスは展開された先のパスを示しています。 Processから取得したパスは生成したExeのパスを示していますね。

上記の差によりPublishSingleFileを指定する前後でアプリの挙動が変わってしまって、大変困った思いをしました。。

以上です。