Встраивание сборок внутри другого узла

Если вы создаете библиотеку классов, которая использует вещи из других сборок, возможно ли внедрить эти другие сборки внутри библиотеки классов в качестве своего рода ресурса?

т.е. вместо того, чтобы MyAssembly.dll, SomeAssembly1.dll и SomeAssembly2.dll сидеть в файловой системе, эти два других файла попадают в MyAssembly.dll и могут использоваться в его коде.


Я также немного смущен тем, почему сборки .NET являются DLL файлами. Разве этот формат не существовал до .NET? Все DLL-библиотеки .NET сборок, но не все DLL файлы являются сборками .NET? Почему они используют один и тот же формат и/или расширение файла?

+38
источник поделиться
7 ответов

Взгляните на ILMerge для объединения сборок.

Я также немного смущен тем, почему сборки .NET являются DLL файлами. Разве этот формат не существовал до .NET?

Да.

Все DLL-сборки .NET сборки,

Либо DLL, либо EXE обычно - но также могут быть netmodule.

но не все DLL файлы являются сборками .NET?

Правильно.

Почему они используют тот же формат и/или расширение файла?

Почему это должно быть по-другому - оно служит той же цели!

+35
источник

ILMerge объединяет сборки, что приятно, но иногда не совсем то, что вы хотите. Например, когда рассматриваемая сборка представляет собой сильно названную сборку, и у вас нет ключа для нее, вы не можете выполнять ILMerge, не нарушая эту подпись. Это означает, что вам нужно развернуть несколько сборок.

В качестве альтернативы ilmerge вы можете встраивать одну или несколько сборок в качестве ресурсов в ваш exe или DLL. Затем во время выполнения, когда сборки загружаются, вы можете программно извлечь встроенную сборку и загрузить и запустить ее. Это звучит сложно, но здесь есть только код шаблона.

Чтобы сделать это, вставьте сборку так же, как вы вставляете какой-либо другой ресурс (изображение, файл перевода, данные и т.д.). Затем настройте AssemblyResolver, который вызывается во время выполнения. Он должен быть установлен в статическом конструкторе класса запуска. Код очень прост.

    static NameOfStartupClassHere()
    {
        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(Resolver);
    }

    static System.Reflection.Assembly Resolver(object sender, ResolveEventArgs args)
    {
        Assembly a1 = Assembly.GetExecutingAssembly();
        Stream s = a1.GetManifestResourceStream(args.Name);
        byte[] block = new byte[s.Length];
        s.Read(block, 0, block.Length);
        Assembly a2 = Assembly.Load(block);
        return a2;
    }

Свойство Name в параметре ResolveEventArgs - это имя сборки, подлежащей разрешению. Это имя относится к ресурсу, а не к имени файла. Если вы вставляете файл с именем "MyAssembly.dll" и вызываете внедренный ресурс "Foo", то здесь вы хотите назвать "Foo". Но это будет путать, поэтому я предлагаю использовать имя файла сборки для имени ресурса. Если вы правильно ввели и назвали свою сборку, вы можете просто вызвать GetManifestResourceStream() с именем сборки и загрузить сборку таким образом. Очень просто.

Это работает с несколькими сборками, так же хорошо, как с одной встроенной сборкой.

В реальном приложении вам захочется улучшить обработку ошибок в этой программе - например, что, если нет потока по данному имени? Что произойдет, если сбой чтения? и т.д. Но это оставалось для вас.

В остальной части кода приложения вы используете типы из сборки как обычно.

Когда вы создаете приложение, вам нужно добавить ссылку на соответствующую сборку, как обычно. Если вы используете инструменты командной строки, используйте параметр /r в файле csc.exe; если вы используете Visual Studio, вам нужно будет "Добавить ссылку..." во всплывающем меню проекта.

Во время выполнения проверка и проверка версии сборки выполняется, как обычно.

Единственное различие заключается в распределении. При развертывании или распространении вашего приложения вам не нужно распространять DLL для встроенной (и ссылочной) сборки. Просто разверните главную сборку; нет необходимости распространять другие сборки, поскольку они встроены в основную DLL или EXE.

+54
источник
другие ответы

Связанные вопросы


Похожие вопросы

может встроить сборку (или любой файл, фактически) в качестве ресурса (а затем использовать класс ResourceManager для доступа к ним), но если вы просто хотите объединить сборки, лучше использовать инструмент, например ILMerge.

EXE и DLL файлы - это переносные исполняемые файлы Windows, которые достаточно общие для размещения будущих типов кода, включая любой .NET-код (они могут также запускается в DOS, но отображается только сообщение о том, что они не должны запускаться в DOS). Они включают инструкции для запуска среды выполнения .NET, если она еще не запущена. Также возможно, чтобы одна сборка охватывала несколько файлов, хотя это вряд ли имеет место.

+7
источник

Примечание. ILMerge не работает со встроенными ресурсами, такими как XAML, поэтому приложения WPF и т.д. должны использовать метод Cheeso.

+5
источник

Там также утилита mkbundle, предлагаемая проект Mono

+4
источник

Почему они используют тот же формат и/или расширение файла?

Почему это должно быть по-другому - оно служит той же цели!

Мой 2-й бит разъяснений здесь: DLL - это динамическая библиотека ссылок. И старые DLL файлы .dll(C-code) и .net.dll по определению являются "динамическими ссылками". Так что .dll является надлежащим описанием для обоих.

0
источник

Что касается ответа Cheeso на встраивание сборок в ресурсы и динамическую загрузку их с помощью перегрузки Load (byte []) с использованием обработчика события AssemblyResolve, вам необходимо изменить распознаватель, чтобы проверить AppDomain на существующий экземпляр сборки для загрузки и возврата существующего экземпляра сборки, если он уже загружен.

Ассембли, загруженные с использованием этой перегрузки, не имеют контекста, что может заставить фреймворк попробовать и перезагрузить сборку несколько раз. Не возвращая уже загруженный экземпляр, вы можете получить несколько экземпляров одного и того же ассемблерного кода и типов, которые должны быть равными, но не будут, поскольку структура считает их состоящими из двух разных сборок.

По крайней мере один из способов, которым будут выполняться несколько событий AssemblyResolve для одной и той же сборки, загруженной в "Без контекста", - это когда у вас есть ссылки на типы, которые он предоставляет из нескольких сборок, загружаемых в ваш AppDomain, так как выполняется код, который нуждается в разрешенных типах.

https://msdn.microsoft.com/en-us/library/dd153782%28v=vs.110%29.aspx

Несколько важных точек из ссылки:

"Другие сборки не могут связываться с сборками, которые загружаются без контекста, если только вы не обрабатываете событие AppDomain.AssemblyResolve"

"Загрузка нескольких сборок с одинаковым идентификатором без контекста может привести к проблемам с типом идентификации, аналогичным тем, которые вызваны загрузкой сборок с одинаковой идентификацией в несколько контекстов. См." Избегайте загрузки сборки в несколько контекстов ".

0
источник

Посмотрите другие вопросы по меткам или Задайте вопрос