这就是我想要做的。我想拥有一个日志活动AssemblyLoadContext实例,以便快速执行已加载的程序集。 当程序集更新事件到来时,我想卸载上下文(我使用的是.net core 3),并使用程序集版本创建新的上下文。但是,当我尝试这样做时,第二次卸载时出现错误
所以我猜我在做某事(非常)错误。我猜测上下文实际上并没有卸载?
如果加载的程序集依赖于某些外部dll,我还会收到一个错误消息,即使该dll位于同一文件夹中,也无法加载。我该如何预防?
任何建议将不胜感激。这是我的代码
class Program
{
private static AssembliesContext assembliesContext;
const int iterations = 10;
static void Main(string[] args)
{
for (int i = 0; i < iterations; i++)
{
assembliesContext = new AssembliesContext();
RunViaReflection();
var wr = new WeakReference(assembliesContext);
assembliesContext.Unload();
assembliesContext = null;
int retries = 0;
while (wr.IsAlive && retries < 5)
{
GC.Collect();
GC.WaitForPendingFinalizers();
retries++;
}
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void RunViaReflection()
{
try
{
string dllPath = Path.Combine(Directory.getcurrentDirectory(),"..","Execution.Sample","bin","Debug","netcoreapp2.2","win10-x64","publish","Execution.Sample.dll");
using (var fs = new FileStream(dllPath,FileMode.Open,Fileaccess.Read))
{
var assembly = assembliesContext.LoadFromStream(fs);
var executableType = assembly.GetTypes()
.Where(x => typeof(IExecutableCode).IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
.FirstOrDefault();
IExecutableCode instance = (IExecutableCode)activator.CreateInstance(executableType);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
public class AssembliesContext : AssemblyLoadContext
{
public AssembliesContext(): base(true)
{
}
protected override Assembly Load(AssemblyName assemblyName)
{
return null;
}
}
修改
我通过将调用结果强制转换为Task来消除错误(因为它是异步方法):
((Task)method.Invoke(instance,new object[] { })).ConfigureAwait(false).Getawaiter().GetResult();
我还像这样加载了相关程序集:
foreach (var ass in assembly.GetReferencedAssemblies())
{
string path = Path.Combine(basePath,$"{ass.Name}.dll");
using (var dependantAssemblyStream = new FileStream(path,Fileaccess.Read))
{
assembliesContext.LoadFromStream(dependantAssemblyStream);
}
}
我仍然想知道如何管理一个寿命长的AssemblyLoadContext,因为如果我尝试将其作为类成员卸载,即使将其设置为null并实例化一个新的类,它也不会卸载。
是否需要其他方法?