[C#.NET] 合併 .net 組件 / 將 .dll 嵌入 .exe

[C#.NET] 合併 .net 組件 / 將 .dll 嵌入 .exe

日前,同事向我反應,應用程式引用太多的 dll 會讓應用程式(exe)資料夾裡有太多的 dll,這看起來很亂。

簡單來說,如何只交付一個檔案,就能讓功能順利執行?如何合并 dll 或是應用程式?

相信,這樣的需求會一直存在,目前我知道有三種方式可以合并 dll。

1.SmartAssembly.exe,需付費,使用簡單,在此就不多說了

SNAGHTML22e75be7

2.ILMerge.exe

保哥有相當詳細的介紹

http://blog.miniasp.com/post/2009/08/07/Useful-tool-ILMerge.aspx

要注意並非所有組件都可合併,若有使用非拖管的組件可能會合併失敗

3.AppDomain.CurrentDomain.AssemblyResolve,利用資源檔動態載入組件


  • 利用 Visual Studio 呼叫 ILMerge.exe 合并組件

Step1.下載安裝ILMerge

http://www.microsoft.com/en-us/download/details.aspx?id=17630

Step2.在Winform專案裡,加入ILMerge 至 Visual Studio(為了讓 ILMerge.exe 上版控)

image

Step3.在Winform專案裡,加入 ResolveAssembly 及 ResolveAssemblyContract 專案,撰寫所需的功能

image

Step4.定義Build Command Line

以下是.NET 4.0的組件用法

ILMerge.exe /log:log.txt  /targetplatform:"v4,c:\windows\Microsoft.NET\Framework\v4.0.30319" /out:Merged.ResolveAssembly.Demo.exe ResolveAssembly.Demo.exe ResolveAssembly.dll ResolveAssemblyContract.dll

image

這樣的用法每次 Build 的時候就會自動合併,為來只要交付 Merged.ResolveAssembly.Demo.exe 及可,同理可証,若你要交付的是 dll 檔就把這個方式用在 dll 專案上

SNAGHTML2300785f


  • 將組件變成資源檔

Step1.加入需要參考的組件至Visual Studio裡,並將建置動作改成 Embedded Resource

image

Step2.在Winform專案裡,加入 ResolveAssembly 及 ResolveAssemblyContract 專案,並設定 Copy Local = false

image

Step3.在程式載入前註冊 AppDomain.CurrentDomain.AssemblyResolve

@Program.cs


using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace ResolveAssembly.Demo
{
    internal static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        private static void Main()
        {
            AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
            
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }

        private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            string resourceName = "ResolveAssembly.Demo." + new AssemblyName(args.Name).Name + ".dll";
            using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
            {
                byte[] assemblyData = new byte[stream.Length];
                stream.Read(assemblyData, 0, assemblyData.Length);
                return Assembly.Load(assemblyData);
            }
        }
    }
}

當應用程式執行時找不到相依組件時,就會依上述程式碼載入組件

下圖為載入ResolveAssembly.Demo.ResolveAssembly.dll

image

下圖為載入ResolveAssembly.Demo.ResolveAssemblyContract.dll

image

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo