単一ファイルのデプロイ
アプリケーションに依存するすべてのファイルを単一のバイナリにバンドルすることで、アプリケーション開発者は、アプリケーションを単一ファイルとして配置し、配布することができます。 フレームワークに依存するデプロイ モデルと自己完結型アプリケーションの両方で、単一ファイルの配置が可能です。
自己完結型アプリケーション内にある単一ファイルは、ランタイム ライブラリとフレームワーク ライブラリが含まれるため、サイズが大きいです。 .NET 6 では、トリミングを発行して、トリム互換アプリケーションの合計サイズを小さくできます。 単一ファイルの配置オプションは、ReadyToRun と Trim の発行オプションと組み合わせることができます。
重要
Windows 7 で単一ファイル アプリを実行するには、.NET Runtime 6.0.3 以降を使用する必要があります。
サンプル プロジェクト ファイル
単一ファイルの発行を指定するサンプル プロジェクト ファイルを次に示します。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<PublishSingleFile>true</PublishSingleFile>
<SelfContained>true</SelfContained>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
</Project>
これらのプロパティには、次の関数があります。
PublishSingleFile
= 単一ファイルの発行を有効にします。 また、dotnet build
時の単一ファイルの警告を有効にします。SelfContained
= アプリが自己完結型またはフレームワーク依存であるかを判断します。RuntimeIdentifier
= ターゲットとする OS と CPU の種類を指定します。 また、既定で<SelfContained>true</SelfContained>
が設定されます。
単一ファイル アプリは常に OS とアーキテクチャに固有です。 Linux x64、Linux Arm64、Windows x64 など、構成ごとに発行する必要があります。
ランタイム構成ファイル (*.runtimeconfig.json や *.deps.json など) は、単一ファイルに含まれています。
単一ファイル アプリを発行する
dotnet publish コマンドを使用して、単一ファイル アプリケーションを発行します。
お使いのプロジェクト ファイルに
<PublishSingleFile>true</PublishSingleFile>
を追加します。この変更により、自己完結型の発行で単一ファイル アプリが生成されます。 また、ビルド時に単一ファイルの互換性に関する警告も表示されます。
<PropertyGroup> <PublishSingleFile>true</PublishSingleFile> </PropertyGroup>
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 を含めるには、DebugType
を embedded
に設定します。 「バンドル内に PDB ファイルを含める」を参照してください。
マネージド C++ コンポーネントは、単一ファイルの配置には適していません。 単一ファイルとの互換性を確保するには、アプリケーションを C# または別の非マネージド C++ 言語で記述することをお勧めします。
ネイティブ ライブラリ
マネージド DLL だけがアプリにバンドルされて、1 つの実行可能ファイルになります。 アプリが起動すると、マネージド DLL が抽出されてメモリに読み込まれ、フォルダーには抽出されません。 この手法により、マネージド バイナリは単一ファイル バンドルに埋め込まれますが、コア ランタイム自体のネイティブ バイナリは別個のファイルになります。
抽出用にそれらのファイルを埋め込み、1 つの出力ファイルを取得するには、IncludeNativeLibrariesForSelfExtract
プロパティを true
に設定します。
IncludeAllContentForSelfExtract
を指定すると、実行可能ファイルを実行する前にすべてのファイル (マネージド アセンブリも) が展開されます。 これは、まれなアプリケーション互換性の問題に役立つ場合があります。
重要
展開が使用されている場合、アプリが起動する前にファイルがディスクに展開されます。
DOTNET_BUNDLE_EXTRACT_BASE_DIR
環境変数がパスに設定されている場合、ファイルはそのパスの下のディレクトリに抽出されます。- それ以外の場合、Linux または macOS で実行されている場合は、ファイルは
$HOME/.net
の下のディレクトリに抽出されます。 - Windows で実行されている場合は、
%TEMP%/.net
の下のディレクトリにファイルが展開されます。
改ざんを防ぐために、これらのディレクトリは、異なる権限を持つユーザーまたはサービスによる書き込みを可能にしないでください。 ほとんどの Linux および macOS システムでは、/tmp または /var/tmp を使用しないでください。
注意
一部の 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"
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> である文字列が返されるか、例外がスローされます。 |
Marshal.GetHINSTANCE |
-1 を返します。 |
Module.Name |
値が <Unknown> である文字列が返されます。 |
一般的なシナリオを修正するための推奨事項がいくつかあります。
実行可能ファイルの隣にあるファイルにアクセスするには、AppContext.BaseDirectory を使用します。
実行可能ファイルのファイル名を見つけるには、Environment.GetCommandLineArgs() の先頭の要素を使用するか、.NET 6 以降では、ProcessPath から返されるファイル名を使用します。
Loose ファイルが完全に配布されないようにするには、埋め込みリソースを使用することを検討します。
バンドル前のバイナリの後処理
一部のワークフローでは、バンドルする前にバイナリの後処理が必要です。 一般的な例は、署名です。 dotnet SDK には、単一ファイルバンドルの直前にバイナリを処理できるようにするための MSBuild 拡張ポイントが用意されています。 使用可能な API は次のとおりです。
GenerateSingleFileBundle
の前に呼び出されるターゲットPrepareForBundle
- バンドルされるすべてのファイルを含む
<ItemGroup><FilesToBundle /></ItemGroup>
- apphost テンプレートを指定するプロパティ
AppHostFile
。 後処理では、apphost を処理から除外した方がよい場合があります。
これをプラグインするには、PrepareForBundle
と GenerateSingleFileBundle
の間で実行されるターゲットを作成する必要があります。
次の .NET プロジェクト Target
ノードの例を考えてみましょう。
<Target Name="MySignedBundledFile" BeforeTargets="GenerateSingleFileBundle" DependsOnTargets="PrepareForBundle">
ツールが署名の過程でファイルをコピーする必要がある可能性があります。 これは、元のファイルがビルドによって所有されていない共有アイテムである場合に発生する可能性があります。たとえば、NuGet キャッシュから取得されるファイルです。 このような場合、ツールは、変更されたコピーを指すように、対応する FilesToBundle
項目のパスを変更することが予想されます。
単一ファイル アプリでアセンブリを圧縮する
埋め込みアセンブリの圧縮を有効にして単一ファイル アプリを作成できます。 EnableCompressionInSingleFile
プロパティを true
に設定します。 生成された単一ファイルには、すべての埋め込みアセンブリが圧縮されており、実行可能ファイルのサイズを大幅に減らすことができます。
圧縮にはパフォーマンス コストが伴います。 アプリケーションの起動時に、アセンブリをメモリに展開する必要があり、この処理に時間がかかります。 使用する前に、圧縮を有効にした場合のサイズ変更と起動コストの両方を測定することをお勧めします。 影響は、アプリケーションによって大きく異なる場合があります。
単一ファイル アプリを検査する
ILSpy ツールを使用して、1 つのファイル アプリを検査できます。 このツールでは、アプリケーションにバンドルされているすべてのファイルを表示し、マネージド アセンブリの内容を検査することができます。
関連項目
.NET