diff --git a/src/AcDream.Core/Plugins/LoadedPlugin.cs b/src/AcDream.Core/Plugins/LoadedPlugin.cs
index ee20c14..a3f6d24 100644
--- a/src/AcDream.Core/Plugins/LoadedPlugin.cs
+++ b/src/AcDream.Core/Plugins/LoadedPlugin.cs
@@ -1,11 +1,20 @@
+using System.Runtime.Loader;
using AcDream.Plugin.Abstractions;
namespace AcDream.Core.Plugins;
+///
+/// Outcome of a plugin load attempt.
+/// On success, is the instantiated plugin,
+/// owns its assembly, and is null.
+/// On failure, and are null and
+/// describes what went wrong.
+///
public sealed record LoadedPlugin(
PluginManifest Manifest,
IAcDreamPlugin? Plugin,
- string? Error)
+ AssemblyLoadContext? LoadContext,
+ Exception? Error)
{
public bool Success => Plugin is not null && Error is null;
}
diff --git a/src/AcDream.Core/Plugins/PluginAssemblyLoadContext.cs b/src/AcDream.Core/Plugins/PluginAssemblyLoadContext.cs
index 9fbc42c..6ce3968 100644
--- a/src/AcDream.Core/Plugins/PluginAssemblyLoadContext.cs
+++ b/src/AcDream.Core/Plugins/PluginAssemblyLoadContext.cs
@@ -10,6 +10,8 @@ namespace AcDream.Core.Plugins;
///
internal sealed class PluginAssemblyLoadContext : AssemblyLoadContext
{
+ private const string AbstractionsAssemblyName = "AcDream.Plugin.Abstractions";
+
private readonly AssemblyDependencyResolver _resolver;
public PluginAssemblyLoadContext(string pluginDirectory, string pluginEntryPath)
@@ -21,7 +23,7 @@ internal sealed class PluginAssemblyLoadContext : AssemblyLoadContext
protected override Assembly? Load(AssemblyName assemblyName)
{
// Share the abstractions assembly with the host — do NOT reload it in the plugin ALC
- if (assemblyName.Name == "AcDream.Plugin.Abstractions")
+ if (assemblyName.Name == AbstractionsAssemblyName)
return null;
var path = _resolver.ResolveAssemblyToPath(assemblyName);
diff --git a/src/AcDream.Core/Plugins/PluginLoader.cs b/src/AcDream.Core/Plugins/PluginLoader.cs
index d3743e6..ba2ba07 100644
--- a/src/AcDream.Core/Plugins/PluginLoader.cs
+++ b/src/AcDream.Core/Plugins/PluginLoader.cs
@@ -5,30 +5,56 @@ namespace AcDream.Core.Plugins;
public static class PluginLoader
{
+ ///
+ /// Load a plugin DLL from into a collectible
+ /// , find the first type
+ /// implementing , instantiate it, and call its
+ /// with the supplied host. Any failure
+ /// is returned as a failed rather than thrown.
+ ///
public static LoadedPlugin Load(string pluginDirectory, PluginManifest manifest, IPluginHost host)
{
var dllPath = Path.Combine(pluginDirectory, manifest.EntryDll);
if (!File.Exists(dllPath))
- return new LoadedPlugin(manifest, null, $"entry dll not found: {dllPath}");
+ return new LoadedPlugin(
+ manifest,
+ Plugin: null,
+ LoadContext: null,
+ Error: new FileNotFoundException($"entry dll not found: {dllPath}", dllPath));
try
{
var alc = new PluginAssemblyLoadContext(pluginDirectory, dllPath);
var asm = alc.LoadFromAssemblyPath(dllPath);
- var pluginType = asm.GetTypes()
+ IEnumerable types;
+ try
+ {
+ types = asm.GetTypes();
+ }
+ catch (ReflectionTypeLoadException rtle)
+ {
+ types = rtle.Types.OfType();
+ }
+
+ var pluginType = types
.FirstOrDefault(t => !t.IsAbstract && typeof(IAcDreamPlugin).IsAssignableFrom(t));
if (pluginType is null)
- return new LoadedPlugin(manifest, null, $"no IAcDreamPlugin implementation found in {manifest.EntryDll}");
+ return new LoadedPlugin(
+ manifest,
+ Plugin: null,
+ LoadContext: null,
+ Error: new InvalidOperationException(
+ $"no IAcDreamPlugin implementation found in {manifest.EntryDll}"));
var instance = (IAcDreamPlugin)Activator.CreateInstance(pluginType)!;
instance.Initialize(host);
- return new LoadedPlugin(manifest, instance, null);
+ return new LoadedPlugin(manifest, instance, alc, Error: null);
}
catch (Exception ex)
{
- return new LoadedPlugin(manifest, null, $"{ex.GetType().Name}: {ex.Message}");
+ return new LoadedPlugin(manifest, Plugin: null, LoadContext: null, Error: ex);
}
}
}
diff --git a/tests/AcDream.Core.Tests/Plugins/PluginLoaderTests.cs b/tests/AcDream.Core.Tests/Plugins/PluginLoaderTests.cs
index 03a07c7..5947e55 100644
--- a/tests/AcDream.Core.Tests/Plugins/PluginLoaderTests.cs
+++ b/tests/AcDream.Core.Tests/Plugins/PluginLoaderTests.cs
@@ -97,6 +97,6 @@ public class PluginLoaderTests
var loaded = PluginLoader.Load(coreDllDir, manifest, host);
Assert.False(loaded.Success);
- Assert.Contains("IAcDreamPlugin", loaded.Error ?? "");
+ Assert.Contains("IAcDreamPlugin", loaded.Error!.Message);
}
}