Как встроить DLL-библиотеки в скомпилированный EXE-файл C#?
Решение: встраивание DLL с помощью Costura.Fody (современный способ)
Самый простой и надёжный способ для .NET Framework, .NET Core и .NET 5+ — использовать пакет Costura.Fody. Он автоматически встраивает все зависимые сборки (DLL) в ваш основной EXE-файл во время сборки. Всё, что вам нужно — установить пакет и добавить одну строку в конфигурацию.
Пошаговая инструкция
- Установите Costura.Fody через NuGet Package Manager или консоль:
Или через .NET CLI:Install-Package Costura.Fodydotnet add package Costura.Fody - Добавьте файл FodyWeavers.xml в корень вашего проекта (если его нет, он создаётся автоматически после установки пакета). Откройте его и убедитесь, что там есть строка:
<Weavers> <Costura /> </Weavers> - Соберите проект — теперь все DLL будут встроены в EXE. Проверьте: удалите все DLL из папки сборки и запустите .exe — он должен работать.
Настройка: исключение определённых сборок
Если вы хотите исключить какие-то DLL из встраивания (например, нативные библиотеки), добавьте атрибуты в FodyWeavers.xml:
<Costura>
<ExcludeAssemblies>
SomeNativeLib
</ExcludeAssemblies>
</Costura>
Как это работает под капотом?
Costura модифицирует ваш EXE на этапе сборки (через MSBuild task). Он добавляет все DLL как встроенные ресурсы (Embedded Resource). При запуске программы срабатывает обработчик события AppDomain.CurrentDomain.AssemblyResolve, который загружает сборки из этих ресурсов. Вам не нужно писать ни строчки кода — всё автоматизировано.
Пример с вашим кодом
После установки Costura.Fody ваш проект будет выглядеть так же, как раньше. Единственный файл, который появится — FodyWeavers.xml. При сборке в папке bin\Release\net6.0 останется только MyApp.exe (и, возможно, .pdb для отладки). Запустите его — Newtonsoft.Json будет загружен изнутри EXE.
Важные замечания
- Производительность: при первом запуске может быть небольшая задержка (доли секунды), так как DLL распаковываются в память. Для большинства приложений это незаметно.
- Нативные DLL: Costura не умеет встраивать нативные библиотеки (C++ DLL). Для них придётся использовать отдельные решения (например, распаковка во временную папку через AssemblyResolve).
- Лицензирование: некоторые библиотеки запрещают встраивание — проверьте лицензию.
- Размер: EXE станет больше на суммарный размер всех DLL. Это нормально.
Альтернатива: ручной AssemblyResolve
Если Costura по каким-то причинам не подходит, можно написать свой обработчик. Вот минимальный пример:
using System;
using System.IO;
using System.Reflection;
class Program
{
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
// Извлекаем имя сборки
string assemblyName = new AssemblyName(args.Name).Name;
// Ищем ресурс с именем "ИмяПроекта.DLLs." + assemblyName + ".dll"
string resourceName = "MyApp.DLLs." + assemblyName + ".dll";
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
if (stream == null) return null;
byte[] assemblyData = new byte[stream.Length];
stream.Read(assemblyData, 0, assemblyData.Length);
return Assembly.Load(assemblyData);
}
};
// Ваш код
var data = new { Name = "Test", Value = 42 };
string json = Newtonsoft.Json.JsonConvert.SerializeObject(data);
Console.WriteLine(json);
}
}
Для этого способа нужно добавить DLL как встроенные ресурсы (Build Action = Embedded Resource) в папку DLLs внутри проекта. Это более трудоёмко, но даёт полный контроль.
Итог
Рекомендую использовать Costura.Fody — это стандарт де-факто для встраивания DLL в .NET. Установка занимает 1 минуту, а результат — чистый и переносимый EXE-файл.
<<Альтернативный подход: публикация как single-file приложение (.NET Core 3.0+)
Если вы используете .NET Core 3.0, .NET 5, 6, 7 или 8, у вас есть встроенная возможность создать single-file приложение без сторонних инструментов. Это не встраивание DLL в EXE, а упаковка всего приложения (включая рантайм и библиотеки) в один файл.
Как это сделать
- Откройте файл проекта (
.csproj) и добавьте или измените свойствоPublishSingleFile:<PropertyGroup> <PublishSingleFile>true</PublishSingleFile> <SelfContained>false</SelfContained> <!-- или true, если хотите включить рантайм --> <RuntimeIdentifier>win-x64</RuntimeIdentifier> </PropertyGroup> - Опубликуйте приложение командой:
Флагdotnet publish -c Release -r win-x64 --self-contained false--self-contained falseозначает, что .NET рантайм не включается (пользователь должен его установить). Если поставитьtrue, получится один EXE, который работает без установленного .NET.
Отличия от Costura.Fody
- Плюсы: не требует дополнительных пакетов, официальная поддержка Microsoft, работает с нативными библиотеками (если они есть).
- Минусы: EXE — это не настоящий «встроенный» файл, а скорее архив. При запуске DLL распаковываются во временную папку (обычно
%TEMP%\.net\). Это может вызвать проблемы с антивирусами или правами доступа. Кроме того, single-file публикация может быть медленнее при первом запуске.
Когда выбирать этот способ
Если вам не нужна поддержка старых .NET Framework (только .NET Core 3+), и вы готовы мириться с распаковкой во временную папку — используйте встроенный single-file. Для максимальной совместимости и простоты лучше взять Costura.Fody.