Страницы

Поиск по вопросам

понедельник, 24 декабря 2018 г.

Как задать структуру выходного проекта?

По умолчанию VS при компиляции кладет все в одну директорию рядом с EXE.
Т.е и сборки и все остальное лежат в одной папке.
Как создать свою собственную структуру?
Например, я хочу, что бы одни сборки клались в одну папку, другие в другую, а в корне был EXE.


Ответ

Ну это как бы можно
Для начала, вы добавляете каталоги, в которых будут лежать ваши библиотеки, в assembly probing path. Для этого отредактируйте ваш app.config, добавьте в него следующее:

(Документация.)
Затем, в свойствах проекта в зависимостях укажите CopyLocal = False:

Затем, в свойствах проекта-библиотеки установите Output Path в каталог, где вы хотите получить эту DLL (для каждого из ваших target platform/processor):

Ну или в post-build step каждого из зависимых проектов укажите вручную копирование куда надо.
Всё, должно работать.

Как советует @Andrew B в комментариях, существует ещё один путь, описанный в документации: подписаться на событие AssemblyResolve, которое отправляется, если .NET не может загрузить сборку из вашего каталога.
Для этого нужен код наподобие такого:
AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve;
где метод OnAssemblyResolve определён так:
Assembly OnAssemblyResolve(object sender, ResolveEventArgs args) { var name = args.Name.Substring(0, args.Name.IndexOf(","));
// проверка на то, есть ли загружаемая сборка среди наших статических ссылок // взята из https://support.microsoft.com/ru-ru/kb/837908 // но вам может быть и не нужна, подумайте сами if (!Assembly.GetExecutingAssembly().GetReferencedAssemblies() .Any(asmName => asmName.FullName.Substring(0, asmName.FullName.IndexOf(",")) == name)) { // это не assembly из наших ссылок return null; }
var applicationDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); foreach (var subfolder in new[] { @"some\subfolder", @"another\subfolder" }) { var path = Path.Combine(applicationDir, subfolder, name + ".dll"; if (File.Exists(path)) return Assembly.LoadFrom(path); }
return null; }
(Не тестировал.)
Достоинство этого решения — то, что список путей можно изменять динамически, если это вдруг понадобилось.
Недостаток — то, что у вас некоторые сборки будут грузиться в assembly binding-контексте LoadFrom в отличие от обычной загрузки в контексте Load. Типы, загруженные в таком контексте, будут несовместимы с типами, загруженными в обычном контексте. Особенно это может «клюнуть», если у вас в разных местах лежат разные версии одной и той же сборки. [Это может привести к эффекту, когда один и тот же статический класс существует в двух экземплярах.] Будьте осторожны и готовы к неожиданностям! (Вопрос также обсуждался здесь.)
Если ваши сборки приходят с ресурсами, возможно, вам нужно учесть эту модификацию
Дополнительное чтение по теме assembly binding/load context:
Best Practices for Assembly Loading Suzanne Cook, LoadFile vs. LoadFrom

Для автоматического копирования сборок в целевые каталоги посредством MSBuild посмотрите ответы к этому вопросу
Но в целом, я бы порекомендовал воспользоваться советом @TomTom и не заморачиваться, а оставить всё как есть. То, что файлы лежат в одном каталоге, пользователь не увидит, если вы правильным образом поместите ярлыки в системное меню при инсталляции (а вы в любом случае должны это сделать).

Комментариев нет:

Отправить комментарий