【问题标题】:Assembly Loading in .NET Core.NET Core 中的程序集加载
【发布时间】:2017-04-15 23:15:05
【问题描述】:

使用 VS2017 RC、.NET Core

我正在尝试从文件加载程序集。 此程序集的依赖项位于同一文件夹中。

我正在使用AssemblyLoadContext.Default.LoadFromAssemblyPath

我意识到LoadFromAssemblyPath 专门加载请求的程序集,忽略它的依赖关系;任何遍历程序集类型的尝试都会失败,并返回 System.Reflection.ReflectionTypeLoadException

LoaderExceptions 包含System.IO.FileNotFoundException 的列表。

我很好奇为什么会这样,因为所有必需的文件都在同一个文件夹中。

我还尝试将所有 *.dll 文件加载到一个文件夹中,但有些意外地以 System.IO.FileLoadException 失败。

我做错了什么?

编辑:我不想依赖 .deps 文件(因此排除了 DependencyContext)。有可能吗?

【问题讨论】:

  • 我不习惯这种操作,但你有没有试过打电话给Assembly.LoadFrom()
  • @Phate01 .NET Core 中没有 Assembly.LoadFrom
  • 我认为您应该通过指定要加载的程序集的名称(全名或短名)从 GAC 加载程序集。但这只是猜测。
  • 已编辑。我不想使用 DependencyContext,因为它需要一个 .deps.json 文件和一个特定的项目配置。在我看来,这太容易错过了。

标签: c# reflection .net-core


【解决方案1】:

对我有用的是使用 Resolving 事件注册一个句柄,并在 LoadFromAssemblyPath 需要依赖项时按需加载所需的程序集。请注意,这是我经过数小时反复试验得出的解决方案,因此它可能不是最理想的方法。不过,它现在对我有用。这是我的代码:

    AssemblyLoadContext.Default.Resolving += (context, name) =>
    {
        // avoid loading *.resources dlls, because of: https://github.com/dotnet/coreclr/issues/8416
        if (name.Name.EndsWith("resources"))
        {
            return null;
        }

        var dependencies = DependencyContext.Default.RuntimeLibraries;
        foreach (var library in dependencies)
        {
            if (IsCandidateLibrary(library, name))
            {
                return context.LoadFromAssemblyName(new AssemblyName(library.Name));
            }
        }

        var foundDlls = Directory.GetFileSystemEntries(new FileInfo(<YOUR_PATH_HERE>).FullName, name.Name + ".dll", SearchOption.AllDirectories);
        if (foundDlls.Any())
        {
            return context.LoadFromAssemblyPath(foundDlls[0]);
        }

        return context.LoadFromAssemblyName(name);
    };
}
private static bool IsCandidateLibrary(RuntimeLibrary library, AssemblyName assemblyName)
{
    return (library.Name == (assemblyName.Name))
            || (library.Dependencies.Any(d => d.Name.StartsWith(assemblyName.Name)));
}

IsCandidateLibrary() 位源自那里: http://www.michael-whelan.net/replacing-appdomain-in-dotnet-core/

我认为您可以省略这个和整个 DependencyContext 部分,但它充当缓存并避免一遍又一遍地重新加载相同的程序集。所以我保留了它。

【讨论】:

    【解决方案2】:

    .Net Core 3.0+ 中有一个很大的增强,如下所示连接AssemblyLoadContext.Default.Resolving 事件,所有依赖项都将被解析和加载:

     AssemblyLoadContext.Default.Resolving += (context, name) => {
                    string assemblyPath = $"{pluginFolder}\\{name.Name}.dll";                
                    if (assemblyPath != null)   
                        return context.LoadFromAssemblyPath(assemblyPath);     
                    return null;
                };
    

    记得定义变量pluginFolder

    解决方案2

    您可以使用AssemblyDependencyResolver 类并解决依赖关系,包括.deps.json 中的依赖关系:

      var resolver = new AssemblyDependencyResolver(pluginPath);            
    
      AssemblyLoadContext.Default.Resolving += (context, name) => {
    
                    string assemblyPath = resolver.ResolveAssemblyToPath(name);               
                    if (assemblyPath != null)   
                        return context.LoadFromAssemblyPath(assemblyPath);     
                    return null;
                };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-15
      • 2020-08-14
      相关资源
      最近更新 更多