Как я могу динамически загружать сборки, на которые ссылается проект, но не на которые ссылается код - PullRequest
0 голосов
/ 18 июня 2019

Рассмотрим приложение .NET Core, которое ссылается на пакет NuGet.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.2</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="MyPackage" Version="1.0.0" />
  </ItemGroup>

</Project>

Если мой код ссылается на тип в MyPackage, тогда будет загружена сборка MyPackage.Если я распечатаю все ссылки или загруженные сборки, то они появятся.

static void Main(string[] args)
{
    // Because I have a reference to a type in MyPackage, the assembly 
    // is loaded and will be printed out by both foreach statements below.
    var throwaway = typeof(MyPackage.Cars);
    foreach (var an in Assembly.GetEntryAssembly().GetReferencedAssemblies())
    {
        WriteLine(an.Name);
    }

    foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
    {
        WriteLine(assembly.FullName);
    }
}

Однако, если я избавлюсь от этой строки throwaway, то сборка будет не загружена ,и поэтому недоступен ни GetReferencedAssemblies, ни GetAssemblies.

. В .NET Framework возникла та же проблема, и исправление обычно состояло в том, чтобы прочитать все сборки в исполняемой папке и загрузить их вручную - что-тонапример:

Directory
    .GetFiles(executingFolder, "*.dll", SearchOption.TopDirectoryOnly)
    .Select(AssemblyLoadContext.Default.LoadFromAssemblyPath));

Однако .NET Core будет загружать сборки из других мест (таких как кеш NuGet - я пока не нашел исчерпывающего описания нового процесса связывания), поэтому приведенное вышеподход не сработает.

Вопрос

Итак, мой вопрос: как я могу динамически загрузить все библиотеки DLL, на которые ссылается мой файл csproj (как NuGet PackageReferences).Мой вариант использования довольно эзотерический, поэтому я не думаю, что подойдет какой-либо другой механизм.

Справочная информация

Хорошо, поэтому кто-то спросит, каков мой вариант использования, так что вот.

У нас есть набор интерфейсов, которые определяют сообщения (IAuditEvent, IValidationEvent, такого рода вещи).У нас также есть различные реализации этих интерфейсов для различных форматов сериализации (Protobuf, XML, JSON и т. Д.).Каждый из них представляет собой отдельный пакет NuGet (MyMessages.Proto, MyMessages.Xml).

У нас есть фабрика, которая создаст соответствующую реализацию (factory.Create<IAuditEvent>()), но она делает это с помощью отражения - например, фабрика прототиповнаходит класс, который реализует IAuditEvent, но также является сгенерированным Protobuf классом.Это не может работать, если сборка не была загружена в первую очередь ...

Ответы [ 2 ]

1 голос
/ 19 июня 2019

Assembly.GetReferencedAssemblies не возвращает вашу сборку, потому что на нее действительно нет ссылок. Если вы посмотрите на манифест exe-файла, вы не найдете ссылку, похоже, что компилятор оптимизирует их.

AppDomain.GetAssemblies возвращает фактически загруженные сборки, рассмотрим:

static void Main(string[] args)
{
    foreach (var an in Assembly.GetEntryAssembly().GetReferencedAssemblies())
    {
        WriteLine(an.Name);
    }

    foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
    {
        WriteLine(assembly.FullName);
    }

    LoadType();
}

static void LoadType()
{
    typeof(MyPackage.Cars);
}

В этом случае результат вызова GetReferencedAssemblies всегда один и тот же, но результат GetAssemblies зависит от того, где вы поместили LoadType - до или после вызова GetAssemblies.

На сервере сборки вы будете собирать решение, а не публиковать его, поэтому сканирование сборок - это только проблема времени разработки. Вы можете добавить следующее в событие после сборки или цель разработки в проекте и использовать один из предложенных Дэниелом методов:

dotnet publish "$ (ProjectPath)" --no-build -o "$ (TargetDir)"

Хотя это далеко от идеала, надеюсь, вы найдете что-то лучшее.

1 голос
/ 19 июня 2019

Это действительно сводится к стратегии на данный момент. Если вам нужен посредник для отражения и предоставления типов, самое время рассмотреть контейнер IoC.

Отсюда у вас есть несколько вариантов:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...