static void ExecuteAndUnload <T>(string modulePath, string resolvePath, Action <T> action, out WeakReference alcWeakRef) where T : class { // Create the unloadable HostAssemblyLoadContext var alc = new ModuleAssemblyLoadContext(resolvePath); // Load System.ComponentModel.TypeDescriptor to the ALC beforehand, // as otherwise the internal caches in it will block unloading the ALC: https://github.com/dotnet/coreclr/issues/26271 // The netstandard assembly shim also needs to be loaded explicitly for the TypeDescriptor to be loaded. var typeDescriptorAssemblyPath = typeof(TypeDescriptor).Assembly.Location; alc.LoadFromAssemblyPath(typeDescriptorAssemblyPath); var netstandardShimAssemblyPath = Path.Combine(Path.GetDirectoryName(typeDescriptorAssemblyPath), "netstandard.dll"); alc.LoadFromAssemblyPath(netstandardShimAssemblyPath); // Create a weak reference to the AssemblyLoadContext that will allow us to detect // when the unload completes. alcWeakRef = new WeakReference(alc); // Load the plugin assembly into the HostAssemblyLoadContext. // NOTE: the assemblyPath must be an absolute path. Assembly a = alc.LoadFromAssemblyPath(modulePath); var assemblyResolverTool = new AssemblyResolverTool(); assemblyResolverTool.dependencyContext = DependencyContext.Load(a); assemblyResolverTool.assemblyResolver = new CompositeCompilationAssemblyResolver (new ICompilationAssemblyResolver[] { new AppBaseCompilationAssemblyResolver(Path.GetDirectoryName(modulePath)), new ReferenceAssemblyPathResolver(), new PackageCompilationAssemblyResolver() }); alc.Resolving += assemblyResolverTool.OnResolving; var module = ResolveTool.ResolveInstance <T>(a); action(module); // This initiates the unload of the HostAssemblyLoadContext. The actual unloading doesn't happen // right away, GC has to kick in later to collect all the stuff. alc.Resolving -= assemblyResolverTool.OnResolving; alc.Unload(); }
static async Task ExecuteAndUnload <T>(string modulePath, string resolvePath, Func <T, Task> action, TaskCompletionSource <WeakReference> tcs) where T : class { try { var alc = new ModuleAssemblyLoadContext(resolvePath); var typeDescriptorAssemblyPath = typeof(TypeDescriptor).Assembly.Location; alc.LoadFromAssemblyPath(typeDescriptorAssemblyPath); var netstandardShimAssemblyPath = Path.Combine(Path.GetDirectoryName(typeDescriptorAssemblyPath), "netstandard.dll"); alc.LoadFromAssemblyPath(netstandardShimAssemblyPath); var alcWeakRef = new WeakReference(alc); Assembly a = alc.LoadFromAssemblyPath(modulePath); var assemblyResolverTool = new AssemblyResolverTool { dependencyContext = DependencyContext.Load(a), assemblyResolver = new CompositeCompilationAssemblyResolver (new ICompilationAssemblyResolver[] { new AppBaseCompilationAssemblyResolver(Path.GetDirectoryName(modulePath)), new ReferenceAssemblyPathResolver(), new PackageCompilationAssemblyResolver() }) }; alc.Resolving += assemblyResolverTool.OnResolving; var module = ResolveTool.ResolveInstance <T>(a); await action(module); alc.Resolving -= assemblyResolverTool.OnResolving; alc.Unload(); tcs.TrySetResult(alcWeakRef); } catch (Exception ex) { tcs.TrySetException(ex); } }