.NET Core中的程序集加载

6

使用VS2017 RC、.NET Core。

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

我正在使用AssemblyLoadContext.Default.LoadFromAssemblyPath

我发现LoadFromAssemblyPath仅加载请求的程序集,忽略其依赖项;任何尝试遍历程序集类型的尝试都会失败,并出现System.Reflection.ReflectionTypeLoadException

LoaderExceptions包含了一个System.IO.FileNotFoundException列表。

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

我还尝试从文件夹中加载所有*.dll文件,但其中一些出乎意料地失败,出现System.IO.FileLoadException

我做错了什么?

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


我不太熟悉这种操作,但你尝试过调用 Assembly.LoadFrom() 吗? - Phate01
1
@Phate01,在.NET Core中没有Assembly.LoadFrom - raine
我认为你应该通过指定要加载的程序集的名称(完整或简短)来从GAC加载程序集。但这只是一个猜测。 - mrogal.ski
1
试一下这个:https://dev59.com/IFoU5IYBdhLWcg3wCjvx#37896162 - Phate01
编辑过的。我不想使用DependencyContext,因为它需要一个.deps.json文件和特定的项目配置。在我看来,这太容易被忽略了。 - raine
2个回答

9

我个人的解决方案是在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部分,但它作为缓存避免了反复加载相同的程序集。因此,我保留了它。


4

从 .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;
            };

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接