ClickOnce 是什麼 - 以實務視角整理機制、更新、適合場面・不適合場面

· · Windows, 發佈, ClickOnce, .NET, Windows 開發

講到發佈 Windows 的 .NET 桌面應用程式,在 MSI 或 MSIX 的陰影下樸素地好幾次出現的名字是 ClickOnce。

但是這裡粗略地,

  • 因為是舊技術所以已經不用
  • 反之,因為看起來簡單所以什麼都能用 ClickOnce

任一種偏向通常都會失準。

ClickOnce 不是什麼都能做的萬能 installer。 另一方面,想對標準使用者發佈公司內部的 .NET 業務應用程式,並把更新都包含低成本地轉動的場面,現在仍然相當有力。

本文以實務視角、加入較多 Mermaid 圖,整理 ClickOnce 是什麼、怎麼運作、什麼優秀、哪裡會有勉強。內容以 2026 年 4 月時點可確認的 Microsoft Learn 資訊為主要前提。

圖是概念圖。在支援 Mermaid 的 Markdown 環境中會顯示為圖。

1. 先講結論

ClickOnce 一句話說就是 把 .NET 的 Windows 桌面應用程式以使用者單位簡單發佈、連自動更新都包含在內轉動的發佈技術

適合的例如以下。

  • WinForms / WPF 等公司內部用業務應用程式
  • 想用標準使用者導入
  • per-user 發佈就夠
  • 想把更新內建
  • 發佈路徑用 Web 網站或檔案分享就夠

相反,以下的話從一開始看別的方式比較安全。

  • 面向全使用者的 machine-wide install
  • Windows service、driver、in-process shell extension、濃的 COM 註冊
  • 需要 package identity
  • 想握有更新頻道、階段發佈、獨自 rollback UX
  • 作為安裝程式對 OS 深入的職責大

簡言之 ClickOnce 是 簡單發佈和簡單更新強,但對 OS 整合重的案件不適合 的方式。

先以一頁看定位

flowchart TD
    A["想發佈 Windows 應用程式"]
    B{"有對 OS 深入整合的要件嗎"}
    C["從 MSI / MSIX 側思考"]
    D{".NET 的 Windows 桌面應用程式<br/>用 per-user 發佈夠嗎"}
    E{"想對標準使用者發佈嗎"}
    F{"built-in 更新夠嗎"}
    G["ClickOnce 有力"]
    H["也比較 xcopy / 獨自 updater"]

    A --> B
    B -- 是 --> C
    B -- 否 --> D
    D -- 否 --> H
    D -- 是 --> E
    E -- 否 --> H
    E -- 是 --> F
    F -- 是 --> G
    F -- 否 --> H

2. ClickOnce 是什麼

ClickOnce 是 Microsoft 的 Windows 應用程式發佈技術。 官方上說明為 以最小的使用者操作就能安裝・執行、能自行更新的 Windows 基礎應用程式的發佈技術

這裡重要的是不要把 ClickOnce 看作單純的「安裝程式的種類」。

實態上 ClickOnce 是一併照料以下的 發佈模型

  • 發佈哪個版本
  • 哪些檔案包含在該版本中
  • 如何檢測更新
  • 從哪裡取得更新
  • 在各使用者的安全位置如何保存
  • 啟動時如何確認整合性

也就是說,ClickOnce 的本體不是 setup.exe 本身。 以 manifest 為中心,一併處理發佈・更新・快取管理的機制 看比較接近本質。

在現行的 .NET 中,ClickOnce 本身普通地作為候選進入。Visual Studio 中 .NET Core 3.1 和 .NET 5 以後用 Publish tool,手動處理 manifest 的情況用 dotnet-mage.exe

ClickOnce 照料的職責

flowchart LR
    CO["ClickOnce"]
    V["發佈哪個版本"]
    U["從哪裡取更新"]
    S["保存到各使用者安全位置"]
    I["確認整合性後啟動"]

    CO --> V
    CO --> U
    CO --> S
    CO --> I

3. 構成 ClickOnce 的東西

理解 ClickOnce 的機制時,看以下 4 個相當容易整理。

要素 角色
佈署 manifest (.application) 表示現在該發佈哪個版本、更新位置、更新方法等
應用程式 manifest (*.exe.manifest) 表示該版本的應用程式本體、依賴檔案、雜湊、進入點等
應用程式檔案 exedll、config、資料檔案等
setup.exe(任意) 確認・導入前提條件的 bootstrapper。有必要執行環境或依賴物時使用

這裡的核心是 2 種 manifest

  • 佈署 manifest 表示「這個應用程式現在的正解是哪個版本」
  • 應用程式 manifest 表示「該版本的內容是什麼」

也就是說,ClickOnce 的更新判定先從佈署 manifest 開始,實際要下載什麼則由應用程式 manifest 握有。

4 要素的關係

flowchart LR
    Setup["setup.exe<br/>任意<br/>前提條件的確認 / 導入"]
    Deploy["佈署 manifest (.application)<br/>發佈哪個版本<br/>更新位置 / 更新條件"]
    App["應用程式 manifest (*.exe.manifest)<br/>該版本的內容<br/>檔案清單 / 雜湊 / 進入點"]
    Files["應用程式本體<br/>exe / dll / config / data"]
    Cache["ClickOnce 快取<br/>per-user / per-application"]

    Setup --> Deploy
    Deploy --> App
    App --> Files
    Files --> Cache

setup.exe 不是主角而是輔助

setup.exe 常被注目,但不是 ClickOnce 的主角。 這是 確認・導入前提條件的輔助角色

例如需要正確的 .NET 執行環境或追加的可轉散發元件時,setup.exe 先準備好,之後再進入 ClickOnce 本體的發佈。

4. 從安裝到啟動的流程

把 ClickOnce 的流程為實務向相當單純化如下。

  1. 使用者打開 Web 頁面或檔案分享上的 setup.exe.application
  2. 使用 setup.exe 的構成的話,確認前提條件並放入不足的
  3. ClickOnce 讀取佈署 manifest
  4. 讀取佈署 manifest 指向的應用程式 manifest
  5. 取得必要的檔案,佈署到各使用者的 ClickOnce 快取
  6. 離線使用有的構成的話,登錄到開始選單或應用程式清單
  7. 之後從 ClickOnce 管理下啟動應用程式

重點是 不是像普通 installer 那樣放到 Program Files 的發想

ClickOnce 應用程式進入 各使用者的安全快取區域,按應用程式・按使用者分離。這裡是 ClickOnce 相當大的特徵。

從安裝到首次啟動

sequenceDiagram
    participant U as 使用者
    participant P as setup.exe / .application
    participant D as 佈署 manifest
    participant A as 應用程式 manifest
    participant C as ClickOnce 快取
    participant X as 應用程式本體

    U->>P: 打開
    Note over U,P: 使用 setup.exe 的構成<br/>先進入前提條件確認
    P->>D: 取得並讀取
    D->>A: 參照對象版本
    A->>C: 取得必要檔案・確認整合性
    C->>X: 佈署並啟動

純線上和有離線使用

ClickOnce 有大致 2 種呈現方式。

  • 純線上: 以公開位置為起點執行的形式。常駐安裝感薄
  • 有離線使用: 導入到使用者的終端,也能從開始選單啟動的形式

公司內部業務應用程式中,實務上多選 有離線使用

flowchart LR
    subgraph Online[純線上]
        O1["以公開位置為起點啟動"]
        O2["常駐安裝感薄"]
        O3["容易變成網路前提"]
        O1 --> O2 --> O3
    end

    subgraph Offline[有離線使用]
        F1["導入到使用者區域"]
        F2["開始選單登錄"]
        F3["從本地啟動"]
        F4["在指定時機確認更新"]
        F1 --> F2 --> F3 --> F4
    end

5. 更新的機制

ClickOnce 最易懂的強處果然還是 更新模型 built-in

更新判定從佈署 manifest 開始

ClickOnce 應用程式讀取佈署 manifest 確認,

  • 是否有新版
  • 是否為必須更新
  • 從哪裡取得

之後更新開始,ClickOnce 用 file patching 避免冗餘的重新下載。感覺上 比較新版的應用程式 manifest 和現行版,只去取變化的檔案,這樣想實務上容易理解。

更新確認的思考方式以下 3 種模式整理比較易懂。

  • 啟動前確認
  • 啟動後確認
  • 在應用程式側準備「更新確認」UI

但是,.NET Framework 和 .NET 5+ 中能用的 API 或設定 UI 有差異。不要只憑舊 ClickOnce 文章的記憶進入實作 很重要。

更新的流程

flowchart TD
    Start["應用程式啟動"]
    Check["確認佈署 manifest"]
    New{"有新版嗎"}
    Run["直接啟動"]
    Get["取得新版的應用程式 manifest"]
    Compare["比較檔案的簽章 / 雜湊"]
    Download["取得變化分"]
    Switch["讓新版成立並切換"]
    Restart["必要時重啟後以新版執行"]

    Start --> Check --> New
    New -- 否 --> Run
    New -- 是 --> Get --> Compare --> Download --> Switch --> Restart

沒有網路連線的情況,不做更新確認直接執行,這個前提也掌握實務上就不易混亂。

版本分離保持

ClickOnce 比起「把現在的檔案當場覆寫」,更接近 讓新版以正確形式成立後切換 的發想。

此外,ClickOnce 快取中 現行版和前版 分離保持。這是不易弄髒環境、易於避免版本衝突的理由之一。

flowchart TB
    subgraph UA[使用者 A 的 ClickOnce 快取]
        APrev["前版"]
        ACur["現行版"]
        AData["設定 / 資料"]
    end

    subgraph UB[使用者 B 的 ClickOnce 快取]
        BPrev["前版"]
        BCur["現行版"]
        BData["設定 / 資料"]
    end

    APrev --> ACur
    AData --> ACur
    BPrev --> BCur
    BData --> BCur

這裡的重點是 2 個。

  • 不易與別的使用者混在一起
  • 不易與別的版本衝突

所謂 DLL Hell 易於避免,就是這個結構很大。

6. ClickOnce 優秀的點

ClickOnce 的好處不只「能簡單發佈」。實務上有效的大致以下。

6.1 易於發佈給標準使用者

ClickOnce 與 per-user 前提的發佈相性好,無需系統管理員權限也易於導入 這點很大。

公司內部業務應用程式常見的是,

  • 使用者是標準使用者
  • 不想每次向 IT 部門請求安裝
  • 但不想停止更新

這種狀況。

這個條件下 ClickOnce 相當強。 「往各使用者的區域,安全地,連更新一起進入」的前提從最初就符合。

6.2 不需要自製更新

從零製作自動更新的話,比外觀更有更多要做的事。

  • 新版確認
  • 下載
  • 整合性確認
  • 與舊版切換
  • 失敗時復原
  • 更新 UI
  • updater 自身的處理

ClickOnce 以既有模型持有其中相當大部分。

flowchart LR
    subgraph Custom[自製 updater 持有的職責]
        C1["新版檢測"]
        C2["下載"]
        C3["整合性確認"]
        C4["切換"]
        C5["失敗時復原"]
        C1 --> C2 --> C3 --> C4 --> C5
    end

    subgraph Click[可靠 ClickOnce 的職責]
        K1["新版檢測"]
        K2["取得與驗證"]
        K3["切換"]
        K1 --> K2 --> K3
    end

當然不是什麼都能自由。 但是 公司內部用應用程式需要的「足夠更新」 相當易於滿足。

6.3 應用程式之間不易衝突

ClickOnce 應用程式 按應用程式・按使用者・按版本分離

所以,舊式的

  • 共用元件的版本競爭
  • 覆寫某處的 DLL 讓別的應用程式壞
  • 手動替換讓環境變髒

這類事故不易發生。

6.4 易於從 Visual Studio 發行

ClickOnce 與 Visual Studio 的發行功能相性好,到發佈的距離短 也是優點。

在進入 MSI authoring 這類其他困難之前,

  • 先發行
  • 先發佈
  • 先轉更新
  • 先獲得現場的回饋

這樣的流程易於製作。

6.5 設定沿用也比較自然

使用預設的應用程式設定 provider 的情況,ClickOnce 有在更新時 把前版的設定合併到新版 的機制。

但這裡是 預設設定 provider 前提。進入獨自設定儲存、獨自 provider、儲存位置的變更的話,當然沒那麼簡單。

7. 適合場面

ClickOnce 特別適合的大致是以下案件。

狀況 與 ClickOnce 相性好的理由
公司內部用 WinForms / WPF 業務應用程式 標準使用者發佈與自動更新契合
使用者單位導入就夠 per-user 發佈自然
想用 Web 網站或 UNC 共享發佈 發佈路徑簡單
更新頻率每月~每週左右 built-in 更新就能充分轉動
不想把更新 UI 當產品價值打磨 能用既有更新模型

舉實務上相當合適的具體例,如下。

  • 公司內部的業務輸入應用程式
  • 估價・接單・庫存等桌面業務工具
  • 裝置設定用的輔助應用程式
  • 發到營業所・工廠・後勤的公司內部專用客戶端
  • 想要更新但做不到專用 updater 程度的應用程式

這樣的應用程式,把發佈和更新做得簡單本身就是價值。ClickOnce 相當自然地回應那個價值。

是否適合的判斷樹

flowchart TD
    S["整理要件"]
    Q1{"是 WinForms / WPF 等的<br/>.NET 桌面應用程式嗎"}
    Q2{"per-user 發佈夠嗎"}
    Q3{"想裝到標準使用者嗎"}
    Q4{"能用 Web / 檔案分享發佈嗎"}
    Q5{"更新 UX 不用打磨過度嗎"}
    G["ClickOnce 相當有力"]
    O["比較其他方式"]

    S --> Q1
    Q1 -- 否 --> O
    Q1 -- 是 --> Q2
    Q2 -- 否 --> O
    Q2 -- 是 --> Q3
    Q3 -- 否 --> O
    Q3 -- 是 --> Q4
    Q4 -- 否 --> O
    Q4 -- 是 --> Q5
    Q5 -- 是 --> G
    Q5 -- 否 --> O

8. 不適合場面

另一方面,不要勉強使用 ClickOnce 的場面也很明確。

8.1 需要 machine-wide install

ClickOnce 基本是 per-user。

  • 想全使用者共通安裝
  • 想以 Program Files 為前提安裝
  • 想對整個終端導入・管理

的話不是 ClickOnce 而是 MSI 等比較自然。

8.2 Windows service / driver / shell extension / 濃的 COM 註冊

這一帶是 對 OS 深入碰觸 的話題。

  • Windows service
  • driver
  • in-process shell extension
  • 以機械性 COM 註冊為前提的構成

進入的話就脫離 ClickOnce 的「輕鬆發佈」的世界觀。

8.3 想要 package identity

選擇 MSIX 的理由之一,有想拿到 package identity 的要件。

ClickOnce 不是這個方向。如果想要 modern packaging 或 Windows 的 package identity 前提功能,優先 MSIX 比較好。

8.4 想把更新 UX 或發佈頻道握為產品

例如,

  • stable / beta / preview 的頻道
  • 階段發佈
  • 看 telemetry 調整推出率
  • 背景下載的細緻控制
  • 獨自的 rollback 策略
  • updater 自身的複雜生命週期

想要這些,ClickOnce 的 built-in 更新會不夠。

8.5 放著用就夠的工具

相反,也有更單純就好的情況。

  • 放整個資料夾就能運作
  • 更新也用手動替換就好
  • 用 USB 交給
  • 在封閉環境單純最優先

的話,xcopy 發佈摩擦較少的情況也有。

什麼要件偏向別方式

flowchart LR
    A1["全使用者用導入"] --> B1["MSI / 一部 MSIX"]
    A2["service / driver / shell extension / 濃的 COM"] --> B2["MSI / 專用 installer"]
    A3["需要 package identity"] --> B3["MSIX"]
    A4["階段發佈 / 頻道 / 獨自 UX"] --> B4["獨自 updater"]
    A5["放著就夠"] --> B5["xcopy"]

也就是說 ClickOnce 向上也向下都不萬能。 是 對剛好的複雜度案件強 的方式。

9. 實務上容易卡的點

ClickOnce 雖然方便,但粗略進入會稍微卡。特別以下先掌握比較輕鬆。

9.1 不要用與「普通 installer」相同感覺看

ClickOnce 不是以固定的安裝位置讓人直接易於管理的形式放的模型。

實體進入 ClickOnce 管理的快取,按版本分離。 所以,

  • 以固定 EXE 路徑為前提的運營
  • 手工直接覆寫的運營
  • 實體檔案位置由人握的運營

相性不好。

ClickOnce 是 檔案佈署不是由人管理的方式,而是以 manifest 管理發佈狀態的方式

9.2 舊 ClickOnce 文章多是 .NET Framework 前提

這裡相當重要。

現在搜尋上位仍然很多是 .NET Framework 時代的 ClickOnce 文章。 但是,現在的 .NET 事情稍微不同。

  • .NET Core 3.1 / .NET 5 / .NET 6 中 ApplicationDeployment API 不能直接使用
  • .NET 7 以後能透過環境變數讀取一部分佈署屬性
  • 手動處理 manifest 的話前提是 dotnet-mage.exe
  • Visual Studio 側也有舊 Publish Wizard 前提的話題直接不通的情況

也就是說 即使「認為懂 ClickOnce」,也不要以舊記憶原樣實作 比較安全。

9.3 前提條件另外考慮

ClickOnce 本身是發佈模型,但應用程式要運作有時需要前提條件。

  • 支援的執行環境
  • 追加的可轉散發元件
  • 其他依賴物

這時使用 setup.exe 的 bootstrapper 構成有效。反之曖昧這裡會發生「ClickOnce 能發佈但不運作」。

9.4 設定的沿用看 “用什麼怎麼儲存”

預設設定 provider 的話更新時的設定遷移比較自然。 但是,

  • 獨自設定 provider
  • roaming 前提
  • 自己改變設定儲存位置
  • 以版本差分大幅改變設定結構

的話,當然沒那麼簡單。

9.5 不要輕忽簽章和更新路徑

ClickOnce 擁有發佈和更新的機制,但不代表安全責任消失。

特別在正式環境,

  • 如何管理簽章憑證
  • 如何顯示發行者名
  • 如何管理更新源
  • 如何分開測試用自簽和正式簽章

最初整理比較好。

flowchart TD
    Cert["程式碼簽章憑證"]
    AppMan["應用程式 manifest"]
    DepMan["佈署 manifest"]
    Verify["在用戶端驗證"]
    Run["更新 / 執行"]
    Tamper["manifest 竄改"]
    Stop["驗證失敗並停止"]

    Cert --> AppMan
    Cert --> DepMan
    AppMan --> Verify
    DepMan --> Verify
    Verify --> Run
    Tamper -. 驗證失敗 .-> Stop

「有自動更新 = 放心」不是,信任什麼、怎麼維持那個信任 需要另外考慮。

9.6 移動佈署處的話重新檢視 deploymentProvider

這很樸素,但實務上相當卡。

已安裝的 ClickOnce 應用程式去看佈署 manifest 內 deploymentProvider 指向的位置當作更新源。 也就是說,就算把公開資料夾整個複製到別 URL 或別分享,不更新 deploymentProvider 的話 客戶端會持續看原位置

然後,如果手動改 manifest,需要 重新簽章

從發行到更新反映的運營流程

flowchart TD
    Build["建置"]
    AppManifest["產生新的應用程式 manifest"]
    SignApp["對應用程式 manifest 簽章"]
    UpdateDep["把佈署 manifest 更新到新版本"]
    SignDep["對佈署 manifest 簽章"]
    Publish["佈署到公開位置"]
    Client["客戶端檢測更新"]

    Build --> AppManifest --> SignApp --> UpdateDep --> SignDep --> Publish --> Client

簡言之,ClickOnce 運營中重要的比起 是否放了檔案,是 manifest 和簽章的整合性是否一致

10. 總結

ClickOnce 一句話說,

把 .NET 的 Windows 桌面應用程式, 用 per-user 簡單發佈、連更新都低成本轉動的機制

優秀的主要是以下點。

  • 易於發佈給標準使用者
  • 有 built-in 的更新模型
  • 易於只更新變化分
  • 易於分離應用程式和版本
  • 易於從 Visual Studio 發行
  • 與公司內部用業務應用程式相性好

但是不萬能。

  • machine-wide install
  • service / driver / shell extension
  • 濃的 COM 註冊
  • package identity
  • 獨自頻道或階段發佈
  • 把更新 UX 當產品價值打磨

有這類要件的話,應該從 MSI / MSIX / 獨自 updater 側而非 ClickOnce 思考。

也就是 ClickOnce 不是 什麼都能進入的簡易 installer。 代替的是 在適合的案件現在仍然相當強

如果想發佈的是

  • .NET 的 Windows 業務應用程式
  • 使用者單位的導入就夠
  • 想發佈到標準使用者
  • 不想自己持有更新

那麼 ClickOnce 相當有力候選。

11. 相關文章

12. 參考資料

共用相同標籤的最新文章。能以相近的主題延伸理解。

與本文相近的主題頁面。以本文為起點,可進一步連到相關服務與其他文章。

本文連結到以下服務頁面,歡迎從最接近的入口查看。

作者檔案

本文作者的個人檔案頁面。

Go Komura

小村軟體有限公司 代表

以 Windows 軟體開發、技術諮詢與故障調查為中心,在難以重現的故障調查與既有資產仍在運作的專案上具有優勢。

回到部落格一覽