Я использую autofac в своем решении для разрешения зависимостей библиотек в разных проектах. Идея состоит в том, чтобы сделать библиотеки горячего подключения в том смысле, что существует всего несколько основных библиотек, от которых зависит приложение, они имеют префикс "vmecore.*.dll"
. Который должен быть зарегистрирован с помощью autofac перед любыми другими библиотеками.
Загружается любая другая библиотека с префиксом «vme. *. Dll», затем я ищу первый тип, реализующий «IVmeExtension», определяющий метод Положить начало(), регистрирую его, активирую и, наконец, инициализирую.
Код, выполняющий регистрацию основных библиотек:
Directory.GetFiles(path, "vmecore.*.dll")
.Select(Assembly.LoadFile)
.ToList()
.ForEach(ass =>
{
//var validAss = Assembly.Load(ass.FullName);
builder.RegisterAssemblyTypes(ass)
.Where(t => t.IsAssignableTo<IVmeExtension>())
.SingleInstance();
//return;
// Iterate through all the types in the assembly
foreach (var type in ass.GetExportedTypes()
.Where(a => a.IsClass &&
!a.IsAbstract &&
a.Namespace != null &&
a.Namespace.Contains(@"VME")))
{
// Get the first type of IVmeExtension
if (!typeof(IVmeExtension).IsAssignableFrom(type)) continue;
//builder.RegisterType(type).SingleInstance();
coreExtension.Add(type);
break;
}
});
Приведенный ниже фрагмент - это делегат обратного вызова, который вызывается при создании контейнера. Базовые библиотеки должны быть разрешены и инициализированы перед горячим подключением расширений, поскольку от них зависит большинство расширений.
//Register a call back when container is built so we can resolve core extensions first
builder.RegisterBuildCallback(container =>
{
coreExtension.ForEach(ext =>
{
try
{
var inst = (IVmeExtension)container.Resolve(ext);
inst.Initiate();
Interface.LogInfo($"VME: Core extension '{inst.Name}'");
}
catch (Exception e)
{
// we log the error here.
throw;
}
});
});
Второе разрешенное расширение требует, чтобы первое было внедрено в конструктор - для этого эксперимента я вручную разрешил его в конструкторе, чтобы увидеть зарегистрированные службы-. Проблема возникает здесь; Я получаю исключение «Запрошенная услуга '..' не зарегистрирована», но глядя на регистрацию, тип там литературный.
Я пробовал решение, предложенное в этом посте https://github.com/autofac/Autofac/issues/593, но когда я это делаю, я получаю исключение системного указателя, и это очень ясно, поскольку при активации экземпляра (var inst = (IVmeExtension)container.Resolve(ext))
среда IDE фактически переводит меня к конструктору совершенно другого class - другой класс находится в исполняющей сборке -
После некоторого времени, по-настоящему покопавшись, я упростил загрузку файлов в это:
var path = "C:\\rust server\\RustDedicated_Data\\Managed";
var coreFiles = Directory.GetFiles(path, "vmecore.*.dll");
var coreExtension = new List<Type>();
// Load each assembly into domain
foreach (var file in coreFiles)
{
var lAssembly = Assembly.LoadFile(file);
var assembly = Assembly.Load(lAssembly.FullName);
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.IsAssignableTo<IVmeExtension>())
.SingleInstance();
// Add all IVmeExtension types
coreExtension.AddRange(assembly.GetExportedTypes()
.Where(a => a.IsClass &&
!a.IsAbstract &&
a.Namespace != null &&
a.Namespace.Contains(@"VME") &&
typeof(IVmeExtension).IsAssignableFrom(a)));
}
Причина, по которой моя исходная версия не работала, заключалась в том, что, хотя сборка файла была загружена, она не была загружена в домен приложения, поэтому, когда я зарегистрировал тип, он получал хэш-код, который использует autofac. Когда приложение пыталось разрешить тип, в этот момент оно загружало сборку в домен приложения. На этом этапе все вновь загруженные типы имеют разные хэш-коды - я предполагаю, что это именно то, что происходило -, что привело к описанной мной ошибке.
Как ни странно, исключение недопустимого указателя, о котором я упоминал, на самом деле возникло, когда второе расширение было активировано и правильно разрешило его зависимости, одно из которых открыло сокет tcp с неправильно набранным IP-адресом (уурхх, коллеги, ага)
Иногда более простой код - лучший код :)
Эти расширения, вероятно, должны инициализироваться из конструктора (и принимать их зависимости, если таковые имеются) - есть ли причина, по которой вы должны сделать это особым случаем с дополнительным вызовом инициализации? Также -
RegisterAssemblyTypes
гарантирует, что это только конкретные классы - поэтому не должно быть причин проверять абстрактные и тому подобное.ToList
тоже кажется лишним. Можете ли вы предоставить MVCE?