Computer common sense c#. Basic use of AssemblyLoadContext in. Net core 3.1

Posted by thewomb on Fri, 12 Nov 2021 18:03:46 +0100

Computer common sense c#. Basic use of AssemblyLoadContext in. Net core 3.1

C#. Basic use of AssemblyLoadContext in. Net core 3.1

preface

Previously used   AppDomain   Wrote a dynamic load and release program case , basically realized the idea of "rabbit dead dog cooking" without leaving any trace. However, in the latest. NET Core 3.1, the creation of a new AppDomain is no longer supported (it is said that the cross platform implementation is too heavy), so it is used instead   AssemblyLoadContext   Yes. However, overall, it feels more intuitive than the original AppDomain.

However, looking for information all the way, I feel that the development of. NET Core to 3.1 has experienced a lot. For example, the API of 2.2 is different from that of 3.1 (in my own experience, the function parameter error will be prompted when the version is changed). The library file cannot be deleted after the AssemblyLoadContext in the preview version is uninstalled, but it will be better after the version is upgraded (a discussion on github)

This article is mainly about the basic use of AssemblyLoadContext, loading and releasing class libraries.

Basic use

The basic function of the program is to dynamically load the required Library of Magick and call its function to compress the given picture. (crooked building, Magick and Android Magick look too similar)

using System;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Loader;

namespace AssemblyLoadContextTest
{
    class Program
    {
        static void Main(string[] args)
        {
            WeakReference weakReference;

            Compress(out weakReference);

            for (int i = 0; weakReference.IsAlive && (i < 10); i++)
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();
            }

            Console.WriteLine($"Uninstall succeeded: {!weakReference.IsAlive}");
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        public static void Compress(out WeakReference weakReference)
        {
            AssemblyLoadContext alc = new AssemblyLoadContext("CompressLibrary", true);	// Create a new AssemblyLoadContext object

            weakReference = new WeakReference(alc);

            Assembly assembly0 = alc.LoadFromAssemblyPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Magick.NET.Core.dll"));
            Assembly assembly1 = alc.LoadFromAssemblyPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Magick.NET-Q16-AnyCPU.dll"));
            
            string filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "image_to_compress.jpg");

            Console.WriteLine("Size before compression:" + new FileInfo(filePath).Length);

            var magickImageType = assembly1.GetType("ImageMagick.MagickImage"); // It is known that this class is defined in assembly1
            var magickImageIns = Activator.CreateInstance(magickImageType, new object[] { filePath });  // magickImageIns = new ImageMagick.MagickImage(filePath)
            var qualityProperty = magickImageType.GetProperty("Quality");
            qualityProperty.SetValue(magickImageIns, 60);   // magickImageIns.Quality = 60
            var writeMethod = magickImageType.GetMethod("Write", new Type[] { typeof(string) });
            writeMethod.Invoke(magickImageIns, new object[] { filePath }); // magickImageIns.Write(filePath)

            Console.WriteLine("Compressed size:" + new FileInfo(filePath).Length);

            var disposeMethod = magickImageType.GetMethod("Dispose");
            disposeMethod.Invoke(magickImageIns, null); // magickImageIns.Dispose()

            //magickImageIns = null;
            alc.Unload();
        }
    }
}

Needless to say, you can create an instance to load; The following points should be noted during uninstallation:

  1. The code loaded and unloaded using AssemblyLoaderContext must be placed in a separate method and cannot be written in the Main method. Otherwise, the loaded module can be unloaded only after the whole program exits
  2. The method should include   [MethodImpl(MethodImplOptions.NoInlining)]   Otherwise, it may not be uninstalled normally (it seems that it is OK not to add it in this example). The official example says:

It is important to mark this method as NoInlining, otherwise the JIT could decide
to inline it into the Main method. That could then prevent successful unloading
of the plugin because some of the MethodInfo / Type / Plugin.Interface / HostAssemblyLoadContext
instances may get lifetime extended beyond the point when the plugin is expected to be
unloaded.

  1. The unloading process is asynchronous and will not be completed immediately after the call
  2. If you have to wait for it to complete, you can create a WeakReference to point to it and judge whether the release is completed by checking whether the WeakReference exists. However, the method waiting for release should be outside the "load and unload code" method, otherwise it can't be seen that it is recycled
  3. It's also strange if I don't add magickImageIns = null at the end; This sentence, sometimes you can uninstall, sometimes you can't uninstall. If a similar situation cannot be uninstalled, you can try it.

TIPS

The module window is provided in Visual Studio to view which assemblies are loaded in time   Debug > Window > module

Simple comparison AppDomain

AppDomain seems to be a large and comprehensive concept, including all aspects of program operation: working path, reference search path, configuration file, shadow copy, etc., while AssemblyLoadContext is just a tool for loading assemblies.

reference resources

Official example (see / Host/Program.cs)

Module windows in Visual Studio
Viewing DLL s and executables - Visual Studio Modules window | Microsoft Docs

This article is very detailed. I haven't studied many problems in depth, but I don't agree with the "put the required variables in the static dictionary. Delete the corresponding Key value before Unload". It may also be because of the version
In depth exploration of the hot plug mechanism of. Net core and the help seeking guide for uninstall problems. - Lao Lu - blog Garden

The questioner inadvertently referenced the AssemblyLoadContext object through ref, which made it impossible to recycle
c# - AssemblyLoadContext did not unload correctly - Stack Overflow

The final test method should be written separately in a method rather than in the Main function (the author didn't explicitly specify it, which has bothered me for a long time)
. NET Core 3.0 recyclable assembly loading context - YOYOFx - blog Garden

Baidu online disk search
www.ijzcn.cn

 

Wow Education
www.awaedu.com
Search whiteness
www.sobd.cc
Brother Cheng
www.jcdi.cn

Topics: C# .NET