Description
Description
My code fails to run when deployed, seem to work when running through VS
Details I have a plugin which im using AssemblyLoadContext and have marked as isCollectible: true
It all seem to work, but does not work when deployed.
every project is on .net 6 to ensure no other variables when trying to debug this AssemblyLoadContext and usage.
-Web
---- Hosts - BackgroundProcessor
-----------Kicks off Plugin code
Only code share with plugin is Component.Facade Lib which has no other references.(it works in VS).
Fails when trying to run plugin code.
I deploy this with self container and targeting Arm32 Release mode, a PI4 with raspberry OS (32bit)
update: confirmed works in Debug but not Release in VS
Exception message:
Could not load file or assembly 'Microsoft.Extensions.Hosting.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. An operation is not legal in the current state. (0x80131509)
Exception inner:
Could not load file or assembly 'Microsoft.Extensions.Hosting.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. An operation is not legal in the current state. (0x80131509) AssemblyLoadContext is unloading or was already unloaded.
my guess the above is this is the issue, but how are you meant to handle this?
the class which kicks off the plugin stuff is TaskComponentProcessor
inside there I have
var pluginInfo = await _taskComponentHelper.EnsureLocalPluginAsync(item.BuilderComponentId.Value);
var pluginLocation = Path.GetFullPath(Path.Combine(pluginInfo.Path, pluginInfo.Name));
var loadContext = new PluginLoadContext(pluginLocation);
var componentUI = loadContext.GetImplementations<BaseComponentUI>().Single();
var plugin = loadContext.GetImplementations<IParadoxComponent>().Single();
i then call
var res = await plugin.ExcuteAsync(executingContext, ct);
code for PluginLoadContext
public class PluginLoadContext : AssemblyLoadContext
{
private AssemblyDependencyResolver _resolver;
private string _path;
public PluginLoadContext() : base(isCollectible: true)
{ }
public PluginLoadContext(string pluginPath) : base(isCollectible: true)
{
_path = pluginPath;
_resolver = new AssemblyDependencyResolver(pluginPath);
}
protected override Assembly Load(AssemblyName assemblyName)
{
if (_resolver != null)
{
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;
}
public IEnumerable<T> GetImplementations<T>()
{
var type = typeof(T);
var assName = AssemblyName.GetAssemblyName(_path);
var assembly = LoadFromAssemblyName(assName);
var types = assembly.GetTypes().ToList();
var other = new List<Type>();
if (type.IsAbstract && !type.IsInterface)
{
other = types.Where(m => m.IsClass && !m.IsAbstract
&& m.IsSubclassOf(type)
).ToList();
}
else
{
other = types.Where(t => type.IsAssignableFrom(t)).ToList();
}
return other
.Select(t => Activator.CreateInstance(t))
.Cast<T>();
}
Statcktrace:
at Paradox.Component.FtpDownloadPlugin.DIBuilder.Start(ExecutingContext e, Action`1 configureDelegate)
at Paradox.Component.FtpDownloadPlugin.Plugin.SetupService(ExecutingContext e, IConfiguration configuration)
in :\Projects\Paradox.Importer\src\ComponentContainer\ComponentFunctions\Paradox.Component.FtpDownload\Plugin.cs:line 31 at Paradox.Component.FtpDownloadPlugin.Plugin.ExcuteAsync(ExecutingContext ec, CancellationToken ct)
in :\Projects\Paradox.Importer\src\ComponentContainer\ComponentFunctions\Paradox.Component.FtpDownload\Plugin.cs:line 58 at Paradox.Component.FtpDownloadPlugin.Plugin.ExcuteAsync(ExecutingContext ec, CancellationToken ct)
in :\Projects\Paradox.Importer\src\ComponentContainer\ComponentFunctions\Paradox.Component.FtpDownload\Plugin.cs:line 93 at Paradox.ComponentCode.TaskComponentProcessor.PreformStepPluginAsync(Int32 actionRequestId, BuilderTaskRun taskRun, BuilderTaskRunItem item, ProgressDto progressDto, IArtifactManger storageManger, CancellationToken ct)
in C:\Projects\Paradox.Importer\src\ComponentContainer\Paradox.ComponentCode\TaskComponentProcessor.cs:line 343
at Paradox.ComponentCode.TaskComponentProcessor.PreformStepPluginAsync(Int32 actionRequestId, BuilderTaskRun taskRun, BuilderTaskRunItem item, ProgressDto progressDto, IArtifactManger storageManger, CancellationToken ct)
in C:\Projects\Paradox.Importer\src\ComponentContainer\Paradox.ComponentCode\TaskComponentProcessor.cs:line 381
at Paradox.ComponentCode.TaskComponentProcessor.ExecuteAsync(Int32 actionRequestId, Int32 builderTaskRunId, CancellationToken ct)
in C:\Projects\Paradox.Importer\src\ComponentContainer\Paradox.ComponentCode\TaskComponentProcessor.cs:line 164
Reproduction Steps
It work when running through VS so, not sure how to debug,
Open to suggestions.
in my plugin i have which i used to return a IServiceProvider so i can register any service the plugin may need.
public class DIBuilder
{
private const string DefaultEnviroementName = "Development";
public static IServiceProvider Start(ExecutingContext e, Action<IServiceCollection> configureDelegate)
{
var configuration = SetConfigation(e);
var host = CreateHostBuilder(configuration, e, configureDelegate).Build();
return host.Services;
}
public static IConfiguration SetConfigation(ExecutingContext e)
{
//this should be local to the plugin and not the app: Hack
var directory = Directory.GetCurrentDirectory();
// e.Logger.LogDebugAsync(directory);
var environment = Environment.GetEnvironmentVariable("ASPNET_ENVIROMENT") ??
Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ??
DefaultEnviroementName;
// e.Logger.LogDebugAsync(environment);
var builder = new ConfigurationBuilder()
.SetBasePath(directory)
.AddJsonFile($"appsettings.json", true, true)
.AddJsonFile($"appsettings.{environment}.json", optional: true, reloadOnChange: true);
IConfiguration configuration = builder.Build();
return configuration;
}
public static IHostBuilder CreateHostBuilder(IConfiguration configuration, ExecutingContext e,
Action<IServiceCollection> configureDelegate, string[] args = null)
{
return Host.CreateDefaultBuilder(args)
.ConfigureServices(configureDelegate);
}
}
Expected behavior
Should not through exception, or at least help with how to fix it.
Actual behavior
fails when deployed, giving the exception
Exception message:
Could not load file or assembly 'Microsoft.Extensions.Hosting.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. An operation is not legal in the current state. (0x80131509)
Exception inner:
Could not load file or assembly 'Microsoft.Extensions.Hosting.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. An operation is not legal in the current state. (0x80131509) AssemblyLoadContext is unloading or was already unloaded.
Regression?
No response
Known Workarounds
No response
Configuration
No response
Other information
No response
Metadata
Metadata
Assignees
Type
Projects
Status