AssemblyLoadContext,动态加载程序集,实例化对象并转换为共享接口
AssemblyLoadContext, dynamically load an assembly, instantiate an object and cast to a shared interface
我正在尝试使用 AssemblyLoadContext
(存在于 netcore 3.0 版)加载一个程序集,实例化一个对象并将该对象转换为一个接口,但是我得到一个转换异常错误。
接口在加载程序集的项目和实例化的实现之间共享。该对象显然已正确实例化,但是当我执行 (T)instance
时出现意外错误。
尝试使用 watcher,我可以按照我正在使用的代码和 watcher 的屏幕截图将实例正确地转换为界面:
private (ExecutionAssemblyLoadContext, T) LoadTheAssemblyAndInstance<T>(string assemblyName, string typeNameToInstance)
{
var basePath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
var assemblyContext = new ExecutionAssemblyLoadContext($"{basePath}/{assemblyName}.dll");
var assembly = assemblyContext.LoadFromAssemblyPath($"{basePath}/{assemblyName}.dll");
var externalCodeEvent = typeNameToInstance != null ? assembly.ExportedTypes
.Where(x => x.FullName == typeNameToInstance)
.Single() : assembly.ExportedTypes.First();
var instance = Activator.CreateInstance(
externalCodeEvent,
_defaultConstructorParameters
);
return (assemblyContext, (T)instance);
}
这是完整的异常消息:
System.InvalidCastException: 'Unable to cast object of type 'Expriva.NewWorkflow.BPMN.ExecutionCodeTest.ExecutionContractTest' to type 'Expriva.NewWorkflow.ExternalShared.Interfaces.IExecutionContract'.'
下面的截图显示T
是由实例实现的
AssemblyLoadContext 支持动态代码加载和卸载,它创建一个独立的上下文来加载代码及其在自己的 AssemblyLoadContext 实例中的依赖项。
问题是在 ExecutionAssemblyLoadContext 实现中,依赖关系被解析和隔离。使用默认实现,由 AssemblyLoadContext 的文档指出,共享类型将不会被隔离。按照正确的实现来使用共享接口。
public class ExecutionAssemblyLoadContext : AssemblyLoadContext
{
public ExecutionAssemblyLoadContext() : base(isCollectible: true)
{
}
protected override Assembly Load(AssemblyName name)
{
return null;
}
}
我也遇到过这个问题,把它想象成不同的 AssemblyLoadContext 有它们自己的加载类型副本,所以尽管你可以在两个上下文中引用共享程序集,但就它们而言,包含的类型是唯一的.
解决方案是在派生的 ALC 中使用加载覆盖从共享上下文解析程序集。
例如,如果将共享类型加载到默认 ALC 中,这很简单。
public class ModAssemblyLoadContext : AssemblyLoadContext
{
public ModAssemblyLoadContext()
: base("ModAssemblyLoadContext", isCollectible: true)
{
}
protected override Assembly Load(AssemblyName assemblyName)
{
return Default.Assemblies
.FirstOrDefault(x => x.FullName == assemblyName.FullName);
}
}
我正在尝试使用 AssemblyLoadContext
(存在于 netcore 3.0 版)加载一个程序集,实例化一个对象并将该对象转换为一个接口,但是我得到一个转换异常错误。
接口在加载程序集的项目和实例化的实现之间共享。该对象显然已正确实例化,但是当我执行 (T)instance
时出现意外错误。
尝试使用 watcher,我可以按照我正在使用的代码和 watcher 的屏幕截图将实例正确地转换为界面:
private (ExecutionAssemblyLoadContext, T) LoadTheAssemblyAndInstance<T>(string assemblyName, string typeNameToInstance)
{
var basePath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
var assemblyContext = new ExecutionAssemblyLoadContext($"{basePath}/{assemblyName}.dll");
var assembly = assemblyContext.LoadFromAssemblyPath($"{basePath}/{assemblyName}.dll");
var externalCodeEvent = typeNameToInstance != null ? assembly.ExportedTypes
.Where(x => x.FullName == typeNameToInstance)
.Single() : assembly.ExportedTypes.First();
var instance = Activator.CreateInstance(
externalCodeEvent,
_defaultConstructorParameters
);
return (assemblyContext, (T)instance);
}
这是完整的异常消息:
System.InvalidCastException: 'Unable to cast object of type 'Expriva.NewWorkflow.BPMN.ExecutionCodeTest.ExecutionContractTest' to type 'Expriva.NewWorkflow.ExternalShared.Interfaces.IExecutionContract'.'
下面的截图显示T
是由实例实现的
AssemblyLoadContext 支持动态代码加载和卸载,它创建一个独立的上下文来加载代码及其在自己的 AssemblyLoadContext 实例中的依赖项。
问题是在 ExecutionAssemblyLoadContext 实现中,依赖关系被解析和隔离。使用默认实现,由 AssemblyLoadContext 的文档指出,共享类型将不会被隔离。按照正确的实现来使用共享接口。
public class ExecutionAssemblyLoadContext : AssemblyLoadContext
{
public ExecutionAssemblyLoadContext() : base(isCollectible: true)
{
}
protected override Assembly Load(AssemblyName name)
{
return null;
}
}
我也遇到过这个问题,把它想象成不同的 AssemblyLoadContext 有它们自己的加载类型副本,所以尽管你可以在两个上下文中引用共享程序集,但就它们而言,包含的类型是唯一的.
解决方案是在派生的 ALC 中使用加载覆盖从共享上下文解析程序集。
例如,如果将共享类型加载到默认 ALC 中,这很简单。
public class ModAssemblyLoadContext : AssemblyLoadContext
{
public ModAssemblyLoadContext()
: base("ModAssemblyLoadContext", isCollectible: true)
{
}
protected override Assembly Load(AssemblyName assemblyName)
{
return Default.Assemblies
.FirstOrDefault(x => x.FullName == assemblyName.FullName);
}
}