單一檔案部署

將所有應用程式相依檔案統合成單一二進位檔,可為應用程式開發人員提供具吸引力的選項,以將應用程式以單一檔案的形式部署及散發。 單一檔案部署適用於架構相依部署模型獨立式應用程式

獨立式應用程式中單一檔案的大小很大,因為其包括執行階段和架構程式庫。 在 .NET 6 中,您可以以修剪的形式發佈以減少修剪相容應用程式的總大小。 單一檔案部署選項可以與 ReadyToRunTrim 發佈選項結合。

重要

若要在 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 命令發佈單一檔案應用程式。

  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 包括在組件中,請將 DebugType 設定為 embedded。 請參閱在套件組合內包括 PDB 檔案

受控 C++ 元件不適合用於單一檔案部署。 建議您使用 C# 或其他非受控 C++ 語言來撰寫應用程式,以使其與單一檔案相容。

原生程式庫

只有受控 DLL 會與應用程式統合成單一可執行檔。 當應用程式啟動時,系統會將受控 DLL 解壓縮並載入記憶體中,以避免解壓縮至資料夾。 使用此方法時,受控二進位檔會內嵌在單一檔案套件組合中,但核心執行階段本身的原生二進位檔會是個別的檔案。

若要內嵌那些檔案以進行解壓縮並取得單一輸出檔案,請將 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 注意
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> 的字串。

我們已提供修正常見案例的一些建議:

統合之前對二進位檔進行後續處理

某些工作流程需要在統合之前對二進位檔進行後續處理。 常見的範例是簽署。 dotnet SDK 提供 MSBuild 擴充點,以允許在單一檔案統合之前處理二進位檔。 可用的 API 包括:

  • 將在 GenerateSingleFileBundle 之前呼叫的目標 PrepareForBundle
  • 包含將統合之所有檔案的 <ItemGroup><FilesToBundle /></ItemGroup>
  • 將指定 apphost 範本的屬性 AppHostFile。 後續處理可能會想要排除 apphost 而不予處理。

若要插入此流程,會牽涉到建立將在 PrepareForBundleGenerateSingleFileBundle 之間執行的目標。

請細想下列 .NET 專案 Target 節點範例:

<Target Name="MySignedBundledFile" BeforeTargets="GenerateSingleFileBundle" DependsOnTargets="PrepareForBundle">

工具可能需要在簽署程序期間複製檔案。 這可能會在原始檔案是組建未擁有的共用項目時發生,例如當該檔案是來自 NuGet 快取時。 在這種情況下,工具預期會修改對應 FilesToBundle 項目的路徑,以指向修改過的複本。

在單一檔案應用程式中壓縮組件

單一檔案應用程式可以在針對內嵌組件啟用壓縮的情況下建立。 將 EnableCompressionInSingleFile 屬性設為 true。 產生的單一檔案會壓縮所有內嵌組件,這可大幅減少可執行檔的大小。

壓縮將伴隨效能成本增加。 在應用程式啟動時,系統必須將組件解壓縮到記憶體中,這需要一些時間。 建議您先測量啟用壓縮的大小變更和啟動成本,再決定是否要使用。 其對不同應用程式所帶來的影響可能會有很大的差異。

檢查單一檔案應用程式

您可以使用 ILSpy 工具 (英文) 來檢查單一檔案應用程式。 此工具可以顯示與應用程式統合的所有檔案,並可檢查受控組件的內容。

另請參閱