Абстрактный метод вызывает исключение ReflectionTypeLoadException в Assembly.GetTypes()C#

Место общения программистов C#
Ответить
Anonymous
 Абстрактный метод вызывает исключение ReflectionTypeLoadException в Assembly.GetTypes()

Сообщение Anonymous »

Я использую архитектуру плагинов в приложении .net 8. Плагины загружаются через:
PluginLoader.cs

Код: Выделить всё

public class PluginLoader
{
private List _plugins = new List();

public PluginLoader(string[] pluginPaths)
{
_plugins = pluginPaths.SelectMany(pluginPath =>
{
Assembly pluginAssembly = LoadPlugin(pluginPath);
return CreatePlugins(pluginAssembly);
}).ToList();
}

public List GetPlugins() => _plugins;

private static Assembly LoadPlugin(string relativePath)
{
// Navigate up to the solution root
string root = Path.GetFullPath(Path.Combine(
Path.GetDirectoryName(
Path.GetDirectoryName(
Path.GetDirectoryName(
Path.GetDirectoryName(
Path.GetDirectoryName(typeof(Program).Assembly.Location)))))));

string pluginLocation = Path.GetFullPath(Path.Combine(root, relativePath.Replace('\\', Path.DirectorySeparatorChar)));

var loadContext = new PluginLoadContext(pluginLocation);
return loadContext.LoadFromAssemblyName(new AssemblyName(Path.GetFileNameWithoutExtension(pluginLocation)));
}

private static IEnumerable CreatePlugins(Assembly assembly)
{
int count = 0;
// EXCEPTION IS HERE
foreach (Type type in assembly.GetTypes())
{
if (typeof(ILmsPlugin).IsAssignableFrom(type))
{
ILmsPlugin result = Activator.CreateInstance(type) as ILmsPlugin;
if (result != null)
{
count++;
yield return result;
}
}
}

if (count == 0)
{
string availableTypes = string.Join(",", assembly.GetTypes().Select(t => t.FullName));
throw new ApplicationException(
$"Can't find any type which implements ILmsPlugin in {assembly} from {assembly.Location}.\n" +
$"Available types: {availableTypes}");
}
}
}

Интерфейс плагинов выглядит следующим образом:
ILmsPlugin.cs
< pre class="lang-none Prettyprint-override">

Код: Выделить всё

public interface ILmsPlugin
{
public string Name { get; }

public string MachineName { get; }

public Type ConfigurationClass { get; }

public void SetConfiguration(string configuration);

public Task CreateQuiz(Quiz quiz);

public ILmsPluginInstanceConfiguration? GetConfiguration();
}
Тогда у меня есть абстрактный класс, реализующий интерфейс:
BaseLmsPlugin.cs

Код: Выделить всё

public abstract class BaseLmsPlugin : ILmsPlugin
{
private ILmsPluginInstanceConfiguration? Configuration { get; set; }

public abstract string Name { get; }

public abstract string MachineName { get; }

public abstract Type ConfigurationClass { get; }

public abstract Task CreateQuiz(Quiz quiz);

public void SetConfiguration(string? configuration)
{
if (configuration == null)
{
return;
}

Configuration = JsonSerializer.Deserialize(configuration, ConfigurationClass) as ILmsPluginInstanceConfiguration;
}

public ILmsPluginInstanceConfiguration? GetConfiguration()
{
return Configuration;
}
}

И, наконец, конкретный класс:

Код: Выделить всё

public class LmsPlugin : BaseLmsPlugin
{
public override string Name { get => "Mock LmsPlugin"; }

public override string MachineName { get => "mock_lmsplugin"; }

public override Type ConfigurationClass { get => typeof(MockLmsPluginConfiguration); }

public override Task  CreateQuiz(Quiz quiz)
{
ILmsPluginQuizOutputDto dto = new LmsPluginQuizOutput
{
Name = quiz.Name,
CourseId = 1
};

return Task.FromResult(dto);
}
}

Это ошибка:

Код: Выделить всё

System.Reflection.ReflectionTypeLoadException : Unable to load one or more of the requested types.
Method 'CreateQuiz' in type 'MockLmsPlugin.LmsPlugin' from assembly 'MockLmsPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.
at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module)
at System.Reflection.RuntimeModule.GetTypes()
at LmsPluginManager.PluginLoader.CreatePlugins(Assembly assembly)+MoveNext() in /Users/[removed]/Sites/[r]]/[r]]/LmsPluginManager/PluginLoader.cs:line 41
at System.Collections.Generic.List`1.AddRange(IEnumerable`1 collection)
at System.Linq.Enumerable.SelectManySingleSelectorIterator`2.ToList()
at LmsPluginManager.PluginLoader..ctor(String[] pluginPaths) in /Users/[removed]/Sites/[r]]/[r]]/LmsPluginManager/PluginLoader.cs:line 12
at Tests.UnitTests.PluginManagerTests.PluginManagerTest.PluginIsAvailableInContainer() in /Users/[removed]/Sites/[r]]/[r]]/Tests/UnitTests/Plugins/PluginManagerTests.cs:line 18
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr)
**Обновление. Я ошибся в отношении приведенной ниже информации: тесты не проходят, поскольку вызывается метод базового класса (BaseLmsPlugin). Я вижу исключение NotImplemented, происходящее в моих тестах. **
Метод наверняка реализован в моем классе. Я концентрируюсь на абстрактном методе, потому что если в моем абстрактном классе (BaseLmsPlugin.cs)
я изменюсь:
< pre class="lang-none Prettyprint-override">

Код: Выделить всё

public abstract Task CreateQuiz(Quiz quiz);
для

Код: Выделить всё

public Task CreateQuiz(Quiz quiz) => throw new System.NotImplementedException();
А затем обновите мой класс до этого:

Код: Выделить всё

public new Task CreateQuiz(Quiz quiz)
{
ILmsPluginQuizOutputDto dto = new LmsPluginQuizOutput
{
Name = quiz.Name,
CourseId = 1
};

return Task.FromResult(dto);
}
тесты пройдут.
Можно ли мне объявить абстрактный метод и при этом заставить плагин загружаться через отражение?
п>

Подробнее здесь: https://stackoverflow.com/questions/790 ... y-gettypes
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»