単一ファイルの配置と実行可能ファイル

アプリケーションに依存するすべてのファイルを単一のバイナリにバンドルすることで、アプリケーション開発者は、アプリケーションを単一ファイルとして配置し、配布することができます。 フレームワークに依存するデプロイ モデル自己完結型アプリケーションの両方で、単一ファイルの配置が可能です。

このデプロイ モデルは、.NET Core 3.0 以降で利用可能であり、.NET 5 で拡張されています。 以前の .NET Core 3.0 では、ユーザーが単一ファイル アプリを実行すると、アプリケーションが実行される前に、まず .NET Core ホストによって、すべてのファイルがディレクトリに展開されます。 .NET 5 では、アプリからファイルを抽出する必要がなく、コードを直接実行するので、このエクスペリエンスが向上しています。

自己完結型アプリケーション内にある単一ファイルは、ランタイム ライブラリとフレームワーク ライブラリが含まれるため、サイズが大きいです。 .NET 6 では、トリミングを発行して、トリム互換アプリケーションの合計サイズを小さくできます。 単一ファイルの配置オプションは、ReadyToRunTrim の発行オプションと組み合わせることができます。

Windows 7 では、単一ファイルを配置できません。

サンプル プロジェクト ファイル

単一ファイルの発行を指定するサンプル プロジェクト ファイルを次に示します。

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

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <PublishSingleFile>true</PublishSingleFile>
    <SelfContained>true</SelfContained>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
    <PublishReadyToRun>true</PublishReadyToRun>
  </PropertyGroup>

</Project>

これらのプロパティには、次の関数があります。

  • PublishSingleFile. 単一ファイルの発行を有効にします。 また、dotnet build 時の単一ファイルの警告を有効にします。
  • SelfContained. アプリが自己完結型またはフレームワーク依存であるかを判断します。
  • RuntimeIdentifier. ターゲットとする OS と CPU の種類を指定します。 また、既定で <SelfContained>true</SelfContained> が設定されます。
  • PublishReadyToRun. Ahead-Of-Time (AOT) コンパイルを有効にします。

単一ファイル アプリは常に OS とアーキテクチャに固有です。 Linux x64、Linux Arm64、Windows x64 など、構成ごとに発行する必要があります。

ランタイム構成ファイル (*.runtimeconfig.json*.deps.json など) は、単一ファイルに含まれています。 追加の構成ファイルが必要な場合は、その単一ファイルの傍らに置くことができます。

単一ファイル アプリを発行する

dotnet publish コマンドを使用して、単一ファイル アプリケーションを発行します。

  1. お使いのプロジェクト ファイルに <PublishSingleFile>true</PublishSingleFile> を追加します。

    この変更により、自己完結型の発行で単一ファイル アプリが生成されます。 また、ビルド時に単一ファイルの互換性に関する警告も表示されます。

    <PropertyGroup>
        <PublishSingleFile>true</PublishSingleFile>
    </PropertyGroup>
    
  2. dotnet publish -r <RID> を使用して、特定のランタイム識別子のアプリを発行します

    次の例では、Windows 用のアプリが自己完結型の単一ファイル アプリケーションとして発行されます。

    dotnet publish -r win-x64

    次の例では、Linux 用のアプリがフレームワークに依存する単一ファイル アプリケーションとして発行されます。

    dotnet publish -r linux-x64 --self-contained false

プロジェクト ファイルに <PublishSingleFile> を設定し、ビルド時にファイル分析を有効にすることもできますが、これらのオプションを dotnet publish 引数として渡すことも可能です。

dotnet publish -r linux-x64 -p:PublishSingleFile=true --self-contained false

詳細については、「.NET CLI を使用して .NET Core アプリを発行する」を参照してください。

ファイルを埋め込み対象から除外する

次のメタデータを設定すると、特定のファイルを単一ファイルの埋め込み対象から明示的に除外することができます。

<ExcludeFromSingleFile>true</ExcludeFromSingleFile>

たとえば、いくつかのファイルを発行ディレクトリに配置するが、そのファイルにはバンドルしない場合などです。

<ItemGroup>
  <Content Update="Plugin.dll">
    <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
    <ExcludeFromSingleFile>true</ExcludeFromSingleFile>
  </Content>
</ItemGroup>

バンドル内に PDB ファイルを含める

アセンブリの PDB ファイルは、次の設定を使用して、アセンブリ自体 (.dll) に埋め込むことができます。 シンボルはアセンブリの一部であるため、アプリケーションの一部でもあります。

<DebugType>embedded</DebugType>

たとえば、アセンブリに PDB ファイルを埋め込むには、そのアセンブリのプロジェクト ファイルに次のプロパティを追加します。

<PropertyGroup>
  <DebugType>embedded</DebugType>
</PropertyGroup>

その他の考慮事項

単一ファイル アプリケーションには、関連するすべての PDB ファイルがアプリケーションと共に含まれますが、既定ではバンドルされていません。 ビルドするプロジェクトのアセンブリ内に PDB を含めるには、DebugTypeembedded に設定します。 「バンドル内に PDB ファイルを含める」を参照してください。

マネージド C++ コンポーネントは、単一ファイルの配置には適していません。 単一ファイルとの互換性を確保するには、アプリケーションを C# または別の非マネージド C++ 言語で記述することをお勧めします。

.NET 3.x との出力の違い

.NET Core 3.x では、単一ファイルとして発行すると、アプリ自体、依存関係、および発行時にフォルダー内に存在した他のファイルで構成される、1 つのファイルが生成されました。 アプリが起動すると、1 つのファイル アプリがフォルダーに抽出され、そこから実行されました。

.NET 5 以降では、マネージド DLL だけがアプリにバンドルされて、1 つの実行可能ファイルになります。 アプリが起動すると、マネージド DLL が抽出されてメモリに読み込まれ、フォルダーには抽出されません。 Windows では、この手法は、マネージド バイナリは単一ファイル バンドルに埋め込まれますが、コア ランタイム自体のネイティブ バイナリは別個のファイルになることを意味します。

.NET Core 3.x のように、展開用にそれらのファイルを埋め込み、1 つの出力ファイルを取得するには、IncludeNativeLibrariesForSelfExtract プロパティを true に設定します。 抽出の詳細については、「ネイティブ ライブラリを含める」を参照してください。

API の非互換性

一部の API は、単一ファイルの配置と互換性がありません。 アプリケーションでこれらの API を使用する場合は、変更が必要になることがあります。 サードパーティのフレームワークまたはパッケージを使用する場合、これらの API のいずれかが使用されているために、変更が必要になる可能性があります。 問題の最も一般的な原因は、アプリケーションに付属するファイルまたは DLL のファイル パスに依存していることです。

次の表に、単一ファイルの使用に関連するランタイム ライブラリ API の詳細を示します。

API Note
Assembly.CodeBase PlatformNotSupportedException をスローします。
Assembly.EscapedCodeBase PlatformNotSupportedException をスローします。
Assembly.GetFile IOException をスローします。
Assembly.GetFiles IOException をスローします。
Assembly.Location 空の文字列を返します。
AssemblyName.CodeBase null を返します。
AssemblyName.EscapedCodeBase null を返します。
Module.FullyQualifiedName 値が <Unknown> である文字列が返されるか、例外がスローされます。
Module.Name 値が <Unknown> である文字列が返されます。

一般的なシナリオを修正するための推奨事項がいくつかあります。

  • 実行可能ファイルの隣にあるファイルにアクセスするには、AppContext.BaseDirectory を使用します。

  • 実行可能ファイルのファイル名を見つけるには、Environment.GetCommandLineArgs() の先頭の要素を使用するか、.NET 6 以降では、ProcessPath から返されるファイル名を使用します。

  • Loose ファイルが完全に配布されないようにするには、埋め込みリソースを使用することを検討します。

デバッガーのアタッチ

Linux では、自己完結型の単一ファイル プロセスにアタッチしたり、クラッシュ ダンプをデバッグしたりできる唯一のデバッガーは、LLDB を使用する SOS です。

Windows と Mac では、Visual Studio と VS Code を使用してクラッシュ ダンプをデバッグできます。 実行中の自己完結型単一ファイルの実行可能ファイルにアタッチするには、追加のファイル mscordbi.{dll,so} が必要です。

このファイルがないと、Visual Studio で次のエラーが発生することがあります: "プロセスにアタッチできません。 デバッグ コンポーネントはインストールされていません。" VS Code で次のエラーが発生することがあります: "プロセスにアタッチできませんでした: 不明なエラー: 0x80131c3c。"

これらのエラーを修正するには、実行可能ファイルの隣に mscordbi をコピーする必要があります。 mscordbi は、既定では、アプリケーションのランタイム ID でサブディレクトリに されます。 そのため、たとえば、Windows 用の dotnet CLI を使用して、自己完結型単一ファイルの実行可能ファイルをパラメーター -r win-x64 を使用して発行する場合、実行可能ファイルは bin/Debug/net5.0/win-x64/publish に配置されます。 mscordbi.dll のコピーは bin/Debug/net5.0/win-x64 にあります。

ネイティブ ライブラリを含める

既定では、単一ファイルの配置では、ネイティブ ライブラリはバンドルされません。 Linux では、ランタイムはバンドルに事前にリンクされ、アプリケーション ネイティブ ライブラリのみが単一ファイル アプリと同じディレクトリに配置されます。 Windows では、ホスト コードのみが事前にリンクされ、ランタイム ライブラリとアプリケーション ネイティブ ライブラリの両方が単一ファイル アプリと同じディレクトリに配置されます。 この手法は優れたデバッグ エクスペリエンスを確保するためのもので、ネイティブ ファイルを単一ファイルから除外する必要があります。

.NET 6 以降、ランタイムはすべてのプラットフォーム上のバンドルに事前にリンクされます。

フラグ IncludeNativeLibrariesForSelfExtract を設定して、ネイティブ ライブラリを単一ファイル バンドルに含めることができます。 これらのファイルは、単一ファイル アプリケーションの実行時にクライアント コンピューター内のディレクトリに展開されます。

IncludeAllContentForSelfExtract を指定すると、実行可能ファイルを実行する前にすべてのファイル (マネージド アセンブリも) が展開されます。 この手法により、元の .NET Core の単一ファイル配置動作が保持されます。

Note

展開が使用されている場合、アプリが起動する前にファイルがディスクに展開されます。

  • 環境変数 DOTNET_BUNDLE_EXTRACT_BASE_DIR がパスに設定されている場合、ファイルはそのパスの下のディレクトリに展開されます。
  • そうでなければ、Linux または MacOS で実行されている場合は、ファイルは $HOME/.net の下のディレクトリに展開されます。
  • Windows で実行されている場合は、%TEMP%/.net の下のディレクトリにファイルが展開されます。

改ざんを防ぐために、これらのディレクトリは、異なる権限を持つユーザーまたはサービスによる書き込みを可能にしないでください。 ほとんどの Linux および MacOS システムでは、/tmp または /var/tmp を使用しないでください。

Note

一部の Linux 環境 (たとえば、systemd の下) では、$HOME が定義されていないため、既定の展開は機能しません。 このような場合は、$DOTNET_BUNDLE_EXTRACT_BASE_DIR を明示的に設定することをお勧めします。

systemd の場合、サービスのユニット ファイルで DOTNET_BUNDLE_EXTRACT_BASE_DIR%h/.net として定義することをお勧めします。これにより、systemd では、サービスを実行しているアカウントの $HOME/.net に正しく展開されます。

[Service]
Environment="DOTNET_BUNDLE_EXTRACT_BASE_DIR=%h/.net"

単一ファイル アプリでアセンブリを圧縮する

.NET 6 以降、埋め込みアセンブリの圧縮を有効にして単一ファイル アプリを作成できます。 EnableCompressionInSingleFile プロパティを true に設定します。 生成された単一ファイルには、すべての埋め込みアセンブリが圧縮されており、実行可能ファイルのサイズを大幅に減らすことができます。

圧縮にはパフォーマンス コストが伴います。 アプリケーションの起動時に、アセンブリをメモリに展開する必要があり、この処理に時間がかかります。 使用する前に、圧縮を有効にした場合のサイズ変更と起動コストの両方を測定することをお勧めします。 影響は、アプリケーションによって大きく異なる場合があります。

関連項目