我經常寫小工具程式,不用安裝程式,單一EXE檔隨Copy隨用是最理想的部署設計。不過,程式稍稍複雜就難免依功能屬性拆分多個專案,有時需用到跨專案的共享程式庫,至於引用Json.NET、Dapper、NLog等必備套件的情況更是普遍。例如以下專案,Tool為Console Application(EXE)專案,引用Model類別程式庫專案,還參考了Json.NET:

編譯後會產生三組組件檔:Tool.exe、Model.dll與Newtonsoft.Json.dll,得一起部署到客戶端才能正確執行。

要實現單一EXE檔搞定,.NET有個好用工具-ILMerge,可將多個DLL、EXE檔合併成單一檔案(ILMerge使用方式可參考保哥的介紹文),原本想花點時間研究怎麼安排AfterPost事件執行ILMerge,驚喜地發現已有好心人包成MSBuild的Task!

在NuGet使用msbuild.ilmerge查詢,可以找到MSBuild.ILMerge.Task,二話不說,安裝到專案。

安裝後專案會多出ILMerge.props、ILMergeOrder.txt,但大部分情況下不需修改,直接編譯就好。

重新編譯可發現Model.dll及Newtonsoft.Json.dll不見了,只剩一個變胖的Tool.exe,使用時只需Copy這個檔案就行了。

用JustDecompile解析,可以看到Tool.exe裡藏了Model跟Newtonsoft.Json組件裡的所有型別。

用這種做法即可輕鬆一檔搞定小工具程式的部署,非常方便。

補充:MSBuild.ILMerge.Task預設會將參照到的DLL都包進EXE檔,如果想略過特定DLL,可將DLL的Copy Local屬性設為False即可排除。


Comments

# by Peter

你好,黑大 最近我用這個套件,發生一個詭異的問題。 就是我專案有個套件,相依於 System.Net.Http.Formatting.dll System.Web.Http.dll (以上兩個都是裝套件產生的) 導致該套件合併失敗..這有解嗎?!

# by Jeffrey

to Peter, 這兩個System.* DLL來自NuGet packages目錄還是GAC?合併錯誤時有錯誤訊息嗎?

# by Peter

黑大,你好 我是安裝 Manatee.Trello.WebApi 這是用來處理 Trello 相關的套件中的一個。 我後來發現他會順便安裝 Microsoft.AspNet.WebApi.Client.5.2.3 (System.Net.Http.Formatting.dll) Microsoft.AspNet.WebApi.Core.5.2.3 (System.Web.Http.dll) 的兩個套件 他會出現這樣的錯誤 ILMerge.Merge: ERROR!!: Duplicate type 'System.Net.Http.HttpRequestMessageExtensions' found in assembly 'System.Web.Http'. Do you want to use the /alllowDup option?

# by livezingy

黑大,您好 我安装了MSBuild.ILMerge.Task,选择“重新生成”是可以成功的;但是在debug或者release模式下,选择“启动”时会报错:尝试运行项目时出错:未能加载文件或程序集或它的某一个依赖项。生成此程序集的运行比当前加载的运行时新,无法加载此程序集。 请问呢这是正常现象吗?原因是什么呢?谢谢解答 :)

# by Jeffrey

to livezingy,我自己的測試未遇過你說的狀況,加上資訊有限,不太能推斷問題所在。建議你另開一個形態類似但極度簡化的專案加上MSBuild.ILMerge.Task,看是否也會遇到相同問題,接著再逐步加入細節調整成會出錯的案例,看在哪一階段出現錯誤有助於找出原因。

# by agrozyme

黑大,您好,我試著安裝 MSBuild.ILMerge.Task,並建立一個空的 WPF 程式,在重建專案時發生這個錯誤訊息,請問該如何排除? MSB4096 The item "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\Microsoft.CSharp.dll" in item list "ReferencePath" does not define a value for metadata "CopyLocal". In order to use this metadata, either qualify it by specifying %(ReferencePath.CopyLocal), or ensure that all items in this list define a value for this metadata. D:\Code\TestDll\cn5ueahs.tmp_proj D:\Code\TestDll\packages\MSBuild.ILMerge.Task.1.0.5\build\MSBuild.ILMerge.Task.targets 35

# by Jeffrey

to agrozyme, 謝謝分享(已筆記)

# by Jake

大大你好 就像你一樣我有成功將dll merge起來(A+B+C) A為主要組件 但我另一個專案參考了這個merged dll 為何無法使用裡面次要組件(B)的類別呢?

# by Jake

補充上面所述 我要使用B dll 裡面的類別 X 若我using B 編譯器會說 X存在於兩個dll(A跟B) 若我不using 會說找不到類型

# by Jeffrey

to Jake, 能提供一個重現問題的小專案嗎?

# by michael

黑大,您好 請問我在NuGet登錄使用msbuild.ilmerge查詢,可以找到MSBuild.ILMerge.Task ,但是下載不下來 他的下載按鈕只顯示 copied 是還需要哪些條件嗎?

# by michael

黑大,您好 請問我在NuGet登錄使用msbuild.ilmerge查詢,可以找到MSBuild.ILMerge.Task ,但是下載不下來 他的下載按鈕只顯示 copied 是還需要哪些條件嗎?

# by Jeffrey

to michael, 沒看過類似狀況,可以貼張圖嗎?

# by michael

如何張貼圖?

# by Jeffrey

to michael, 如果沒有慣用的分享來源,可以用 https://imgur.com/

# by Aaron

黑大,您好 請問這方法是否不支援VS2022?我下載安裝完,重新建置就報錯了,無法生成單一EXE檔,移除後,又可以生成。

# by Jeffrey

to Aaron, 我找不到測試用的專案了,能弄個重現問題的小專案丟上 Github 嗎?

# by Aaron

等待複核中,留言將在稍後顯示 / The comment is awaiting review.

# by Aaron

黑大 您好: 請教上傳的檔案似否有解套的方式?謝謝!

# by Jeffrey

to Aaron, (不好意思,上則留言從待辦區掉進柴米油鹽裡,現在才被喚醒) 依據錯誤訊息提示,我在 vbproj 加上 ILMergeDebugInfo false 設定,問題似乎就排除了,你試試看。 <PropertyGroup> <!--- 略 ---> <UseWindowsForms>true</UseWindowsForms> <MyType>WindowsForms</MyType> <ILMergeDebugInfo>false</ILMergeDebugInfo> </PropertyGroup>

# by Aaron

黑大 您好: 依你所述,建置後無法生成執行檔....執行訊息如下: 1>------ 已開始建置: 專案: Get_HDD_SN, 設定: Debug Any CPU ------ 1>Merge PDBs: false 1>Merged assemblies: D:\WORK\VB\Get_HDD_SN\obj\Debug\net8.0-windows\Get_HDD_SN.dll; 1>C:\Users\Administrator\.nuget\packages\msbuild.ilmerge.task\1.1.3\build\MSBuild.ILMerge.Task.targets(88,5): warning : Specified merge order file 'D:\WORK\VB\Get_HDD_SN\ILMergeOrder.txt' doesn't exist. 1>專案 "Get_HDD_SN.vbproj" 建置完成。 有否解決方式?謝謝

# by Jeffrey

等待複核中,留言將在稍後顯示 / The comment is awaiting review.

Post a comment