Вот что я сделал до сих пор: я изменил тип вывода основного веб-приложения на «Библиотека» и создал небольшую программу-загрузчик, которая загружает эту DLL и ее зависимости в HostAssemblyLoadContext, а затем вызывает исходный метод Main(). Серверное приложение запрограммировано на корректное завершение работы через несколько секунд после запуска, поэтому методы CreateHostBuilder(args).Build().Run() и Main() могут вернуться. После этого я пытаюсь вызвать HostAssemblyLoadContext.Unload(), но по какой-то причине контекст загрузки отказывается выгружаться.
Вот моя реализация HostAssemblyLoadContext:
Код: Выделить всё
public class HostAssemblyLoadContext : AssemblyLoadContext
{
private readonly AssemblyDependencyResolver _resolver;
public HostAssemblyLoadContext(string pluginPath) : base(isCollectible: true)
{
_resolver = new AssemblyDependencyResolver(pluginPath);
}
protected override Assembly? Load(AssemblyName name)
{
string? assemblyPath = _resolver.ResolveAssemblyToPath(name);
if (assemblyPath != null)
return LoadFromAssemblyPath(assemblyPath);
string filePath = $"{name.FullName.Split(',')[0]}.dll";
if(File.Exists(filePath))
return Assembly.LoadFrom(filePath);
return null;
}
}
Код: Выделить всё
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ExecuteMainMethod(string[] args, string assemblyFileName, out WeakReference contextReference, out HostAssemblyLoadContext loadContext)
{
loadContext = new HostAssemblyLoadContext(new DirectoryInfo(".").FullName);
contextReference = new WeakReference(loadContext);
var assembly = loadContext.LoadFromAssemblyPath(assemblyFileName);
var mainMethod = FindMainMethod(assembly)!;
try
{
mainMethod.Invoke(null, new object?[] {args});
}
catch
{
// ignore
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void Unload(WeakReference weakReference, ref HostAssemblyLoadContext loadContext)
{
loadContext.Unload();
loadContext = null;
for (int i = 0; weakReference.IsAlive && i < 100; i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
Console.WriteLine($"is alive: {weakReference.IsAlive}");
}
public static void Main(string[] args)
{
ExecuteMainMethod(args, new FileInfo("FirestormSW.SmartGrade.dll").FullName, out var weakReference, out var loadContext);
Unload(weakReference, ref loadContext);
Console.Out.WriteLine("Press ENTER to exit");
Console.ReadLine();
}
Код: Выделить всё
public static void Main(string[] args)
{
Console.Out.WriteLine("Starting Server...");
CreateHostBuilder(args).Build().Run();
Console.Out.WriteLine("Server stopped.");
}
Когда я запускаю эту программу и жду, пока сервер выключится, вот что я вижу на консоли:
Код: Выделить всё
Starting Server...
Shutting down...
is alive: True
Код: Выделить всё
Process.GetCurrentProcess().Threads.Count