Бывает приходится разработать маленькое приложение на C# и WPF, однако в следствие использования сторонних сборок(например SharpZipLib, Unity) — получается так что на выходе у нас кроме нашего маленького .exe-шника получается ещё и куча .dll-ок, а нам нужно чтобы был именно один .exe-шник.
Немногие знающие люди тут вспомнят про утилиту ILMerge от Microsoft, но к несчастью — есть проблемы с WPF-приложениями из-за особенностей компиляции XAML-файлов.
Так же бывают проблемы с хитрыми сборками, по которым прошлись приличными обфускаторами.
Я предлагаю другой выход который и использую в некоторых своих продуктах — включить все сторонние сборки как встраиваемые ресурсы(embedded resource), а в App.xaml.cs сделать так:
Соответственно с таких подходом мы подразумеваем что мы нормально называем файлы сборок.
Важно помнить что этим методом я лишь показываю идею, тут нету ни обработчиков возможных ошибок, ни многого всего другого.
Что ещё можно улучшить — можно уменьшить размер выходного .exe-шника храня сборки сжатыми через DeflateStream и считывая их соответственно распаковывая через него же. Можно периодически проверять не обновилась ли сборка и если обновилась — грузить её из сети (особенно если это чтото мелкое).
И да, важный момент, что скорее всего не будет работать — при такой сборке скорее всего не будут работать сборки с нативными методами, т.е. написанные на C++/CLI. Поправьте меня если я ошибаюсь, но у меня не работали.
[update]
Насчёт C++/CLI — согласно MSDN — выкидывается исключение BadImageFormatException в случае если компилятор C++ удалил .reloc секцию из .exe-шника. Если скомпилировать сборку на C++/CLI с /fixed:no то возможно она будет успешно загружаться
Немногие знающие люди тут вспомнят про утилиту ILMerge от Microsoft, но к несчастью — есть проблемы с WPF-приложениями из-за особенностей компиляции XAML-файлов.
Так же бывают проблемы с хитрыми сборками, по которым прошлись приличными обфускаторами.
Я предлагаю другой выход который и использую в некоторых своих продуктах — включить все сторонние сборки как встраиваемые ресурсы(embedded resource), а в App.xaml.cs сделать так:
- public partial class App : Application
- {
- //Обработчик события запуска приложения
- private void OnStartup(object sender, StartupEventArgs e)
- {
- //Для текущего домена приложения вешаем свой обработчик в котором и будем вручную подсовывать нужные сборки
- AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;
- }
-
- //Наш обработчик для резолва сборок
- static Assembly ResolveAssembly(object sender, ResolveEventArgs args)
- {
- //Получаем текущую сборку которая выполняется(чтобы из нее брать ресурсы)
- Assembly thisAssembly = Assembly.GetExecutingAssembly();
- //Формируем имя ресурса
- var name = args.Name.Substring(0, args.Name.IndexOf(',')) + ".dll";
- //Находим ресурс по имени
- var resourceName = thisAssembly.GetManifestResourceNames().First(s => s.EndsWith(name));
-
- using (Stream stream = thisAssembly.GetManifestResourceStream(resourceName))
- {
- //Считываем ресурс в массив байтов
- byte[] block = new byte[stream.Length];
- stream.Read(block, 0, block.Length);
- //Загружаем сборку из массива байтов в текущий домен приложения и возвращаем её
- return Assembly.Load(block);
- }
- }
- }
* This source code was highlighted with Source Code Highlighter.
Соответственно с таких подходом мы подразумеваем что мы нормально называем файлы сборок.
Важно помнить что этим методом я лишь показываю идею, тут нету ни обработчиков возможных ошибок, ни многого всего другого.
Что ещё можно улучшить — можно уменьшить размер выходного .exe-шника храня сборки сжатыми через DeflateStream и считывая их соответственно распаковывая через него же. Можно периодически проверять не обновилась ли сборка и если обновилась — грузить её из сети (особенно если это чтото мелкое).
И да, важный момент, что скорее всего не будет работать — при такой сборке скорее всего не будут работать сборки с нативными методами, т.е. написанные на C++/CLI. Поправьте меня если я ошибаюсь, но у меня не работали.
[update]
Насчёт C++/CLI — согласно MSDN — выкидывается исключение BadImageFormatException в случае если компилятор C++ удалил .reloc секцию из .exe-шника. Если скомпилировать сборку на C++/CLI с /fixed:no то возможно она будет успешно загружаться