Пользовательский AssemblyLoadContext не может загрузить Microsoft.AspNetCore.Components - PullRequest
0 голосов
/ 25 октября 2019

Редактировать: Я загрузил исходный код проблемы в GitHub, если вы хотите загрузить: https://github.com/bryanenroute/assemblyloadcontext-issue

У меня есть консольное приложение .NET Core 3.0, которое ссылается на стандарт .NETБиблиотека классов 2.0 с единым интерфейсом (IModule). У меня также есть приложение ASP.NET Core 3.0, которое ссылается на ту же библиотеку классов .NET Standard 2.0 и реализует интерфейс (Module: IModule).

Я пытаюсь загрузить сборку ASP.NET Core из. Консольное приложение NET Core, использующее пользовательский AssemblyLoadContext и общий интерфейс библиотеки классов (IModule) ... простая система плагинов.

К сожалению, модуль / плагин ASP.NET Core не работает в функции переопределения ALC для Load (AssemblyName) со следующим исключением:

Не удалось загрузить файл или сборку 'Microsoft.AspNetCore.Components, версия = 3.0.0.0, культура = нейтральная, PublicKeyToken = adb9793829ddae60'. Системе не удается найти указанный файл.

Когда я пытаюсь использовать другой тип проекта (например, .NET Core Console Application или .NET Standard 2.0 Class Library), модуль / плагин загружается, как предполагалось.

Вот код консольного приложения:


using NetStandardCommon;
using System;
using System.IO;

namespace NetCoreConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            LoadNetCoreModule();
            LoadAspNetCoreModule();
        }

        static void LoadNetCoreModule()
        {
            //Works!
            FileInfo asm = new FileInfo(@"..\..\..\..\NetCoreModule\bin\debug\netcoreapp3.0\NetCoreModule.dll");
            var moduleDirectory = asm.DirectoryName;

            ModuleAssemblyLoadContext context = new ModuleAssemblyLoadContext(asm.Name, moduleDirectory, typeof(IModule));
            context.Scan();

            foreach (var module in context.GetImplementations<IModule>())
            {
                module.Start();
            }
        }

        static void LoadAspNetCoreModule()
        {
            //Fails!
            FileInfo asm = new FileInfo(@"..\..\..\..\AspNetCoreApp\bin\debug\netcoreapp3.0\AspNetCoreApp.dll");
            var moduleDirectory = asm.DirectoryName;

            ModuleAssemblyLoadContext context = new ModuleAssemblyLoadContext(asm.Name, moduleDirectory, typeof(IModule));
            context.Scan();

            foreach (var module in context.GetImplementations<IModule>())
            {
                module.Start();
            }
        }
    }
}


Вот код ModuleAssemblyLoadContext:

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
using System.Linq;

namespace NetCoreConsoleApp
{
    public class ModuleAssemblyLoadContext : AssemblyLoadContext
    {
        private List<Assembly> _loaded;
        private Dictionary<string, Assembly> _shared;

        private string _path;

        private AssemblyDependencyResolver _resolver;

        public ModuleAssemblyLoadContext(string name, string path, params Type[] sharedTypes) : base(name)
        {
            _path = path;
            _resolver = new AssemblyDependencyResolver(_path);

            _loaded = new List<Assembly>();
            _shared = new Dictionary<string, Assembly>();

            if (sharedTypes != null)
            {
                foreach (Type sharedType in sharedTypes)
                {
                    _shared[Path.GetFileName(sharedType.Assembly.Location)] = sharedType.Assembly;
                }
            }
        }

        public void Scan()
        {
            foreach (string dll in Directory.EnumerateFiles(_path, "*.dll"))
            {
                var file = Path.GetFileName(dll);

                if (_shared.ContainsKey(file))
                {
                    continue;
                }

                var asm = this.LoadFromAssemblyPath(dll);

                _loaded.Add(asm);
            }
        }

        public IEnumerable<T> GetImplementations<T>()
        {
            return _loaded
                .SelectMany(a => a.GetTypes())
                .Where(t => typeof(T).IsAssignableFrom(t))
                .Select(t => Activator.CreateInstance(t))
                .Cast<T>();
        }

        protected override Assembly Load(AssemblyName assemblyName)
        {
            string filename = $"{assemblyName.Name}.dll";
            if (_shared.ContainsKey(filename))
            {
                return _shared[filename];
            }

            string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
            if (assemblyPath != null)
            {
                return LoadFromAssemblyPath(assemblyPath);
            }

            return null;
        }

        protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
        {
            string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
            if (libraryPath != null)
            {
                return LoadUnmanagedDllFromPath(libraryPath);
            }

            return IntPtr.Zero;
        }
    }
}


Я попытался изменить функцию загрузки ALC для загрузки сборок непосредственно из общей папки. (C: \ Program Files (x86) \ dotnet \ shared \ Microsoft.AspNetCore.App \ 3.0.0), которая позволяет продолжить выполнение немного дальше, но в конечном итоге происходит сбой со следующим исключением:

Была предпринята попытка загрузить программу с неверным форматом. (0x8007000B)

Вот пересмотренная функция загрузки:

        protected override Assembly Load(AssemblyName assemblyName)
        {
            string filename = $"{assemblyName.Name}.dll";
            if (_shared.ContainsKey(filename))
            {
                return _shared[filename];
            }

            try
            {
                if (File.Exists(@"C:\Program Files (x86)\dotnet\shared\Microsoft.AspNetCore.App\3.0.0\" + filename))
                {
                    return Assembly.LoadFrom(@"C:\Program Files (x86)\dotnet\shared\Microsoft.AspNetCore.App\3.0.0\" + filename);
                }
            }
            catch (Exception ex)
            {
                //Message displayed is 'An attempt was made to load a program with an incorrect format. (0x8007000B)'
                Console.WriteLine(ex.Message);
            }

            return Assembly.Load(assemblyName);
        }

Я в восторге от возможностей загрузки / выгрузки сборок для системы плагинов .net Core, но яЯ изо всех сил пытаюсь преодолеть это препятствие. Чего мне не хватает?

Ответы [ 2 ]

0 голосов
/ 28 октября 2019

Я полагаю, что библиотеку также необходимо собирать с целевым фреймворком, установленным на .NetCore 3.0 (netcoreapp3.0).

0 голосов
/ 25 октября 2019

У меня была эта проблема около месяца назад с загрузкой Assembly на мой SQL-сервер. Используете ли вы виртуальные диски для хранения вашей сборки? Я обнаружил, что фактический путь к нашему общему диску - это диск E, а не диск P, который отображается на моем компьютере. Я был практически подключен к нему, поэтому мне пришлось указать реальный путь к диску, который начинался с буквы E вместо P. Кроме того, ваша программа также может отображать его на неправильный диск. Я бы проверил это, и если это не поможет, у меня есть еще 3-4 вещи, чтобы попытаться решить этот конкретный вопрос.

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