从AppDomain迁移到AssemblyLoadContext

  • 2020 年 2 月 12 日
  • 笔记

AssemblyLoadContext

基本上AssemblyLoadContext是AppDomain的继承者,它提供相同而且更多的功能-除了安全边界(隔离)。最小的安全边界是进程,因此你将需要使用进程间通信来正确隔离数据和代码执行。

官网文档中提到Appdomain已经过时了,为了兼容旧的版本,提供了部分功能。建议在.NET Core3.0及更高的版本使用AssemblyLoadContext。

从AppDomain迁移到AssemblyLoadContext

也许你仍在应用程序中使用AppDomain。现在,以下代码显示如何用AssemblyLoadContext的相应方法去替换掉AppDomain方法:

  • 获取所有程序集
var assembliesInAppDomain = AppDomain.CurrentDomain.GetAssemblies();  var assembliesInAssemblyLoadContext = AssemblyLoadContext.Default.Assemblies;
  • 加载一个程序集
AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName("path"));  AssemblyLoadContext.Default.LoadFromAssemblyName(AssemblyName.GetAssemblyName("path"));
  • 加载一个程序集 路径或者字节数组:
AppDomain.CurrentDomain.Load(File.ReadAllBytes("path"));  AssemblyLoadContext.Default.LoadFromStream(File.OpenRead("path"));  // or  AssemblyLoadContext.Default.LoadFromAssemblyPath("path");
  • 测试封装的获取程序集方法GetAssemblies

准备工作:

  1. 创建一个控制台程序
  2. 添加一个类库项目,命名为AA.Service

在控制台应用程序,添加一个类TypeFinder代码如下:

 public class TypeFinder      {          /// <summary>          /// 获取物理路径          /// </summary>          /// <returns>binDebugnetcoreapp3.0</returns>          public virtual string GetBinDirectory()          {              return AppContext.BaseDirectory;          }          /// <summary>          /// 获取程序集          /// </summary>          /// <returns></returns>          public IList<Assembly> GetAssemblies()          {              var binPath = GetBinDirectory();              var addedAssemblyNames = new List<string>();              var assemblies = new List<Assembly>();                //              foreach (var assembly in AssemblyLoadContext.Default.Assemblies.Where(a=>IsNotSysAssembly(a.FullName)))              {                  if (addedAssemblyNames.Contains(assembly.FullName))                      continue;                  addedAssemblyNames.Add(assembly.FullName);              }                foreach (var dllPath in Directory.GetFiles(binPath, "*.dll",                   SearchOption.TopDirectoryOnly))              {                  try                  {                      var an = AssemblyName.GetAssemblyName(dllPath);                      if (!addedAssemblyNames.Contains(an.FullName))                      {                          AssemblyLoadContext.Default.LoadFromAssemblyName(an);                      }                  }                  catch (BadImageFormatException ex)                  {                      Trace.TraceError(ex.ToString());                  }              }                foreach (var assembly in AssemblyLoadContext.Default.Assemblies.Where(a => IsNotSysAssembly(a.FullName)))              {                  if (addedAssemblyNames.Contains(assembly.FullName))                      continue;                    assemblies.Add(assembly);              }              return assemblies;          }            /// <summary>          /// 排除系统程序集          /// </summary>          /// <param name="assemblyName"></param>          /// <returns></returns>          private bool IsNotSysAssembly(string assemblyName)          {              return !assemblyName.StartsWith("Microsoft.")                        && !assemblyName.StartsWith("System.")                        && !assemblyName.StartsWith("Newtonsoft.")                        && assemblyName != "netstandard";          }      }

在控制台应用程序添加引用AA.Service类库,生成查看bin文件,出现了AA.Service.dll

调用代码输出(排除系统dll以Microsoft、system开头的)程序集:

var assemblies= new TypeFinder().GetAssemblies();              foreach (var a in assemblies)              {                  Console.WriteLine(a.FullName);              }

输出