.Net core手动加载dll,无法自动加载其依赖项

net core手动加载dll,无法自动加载其依赖项

用的net core版本是2.1,也许在后续的版本中已经修复了这个问题。

今天在尝试用net core写demo的时候,发现了这个问题。因为都是使用DI,所以就没有在我的网站项目里直接引用一些实现类库,而是放到了同一个目录下,在网站启动的时候用代码去加载进来。然而在实际的运行过程中发现,指定的dll会自动加载,但是其依赖的nuget包里的dll不会被加载进来。在Google了很久,也发现了很多人提出过这个问题,在GitHub上也有人提过这里,但是都没有直接的解决方案,其中有一个差不多的解决方案CodeProject上的解决方案,我的解决方案也是依据这个改进而来的。

代码的核心思路是去找需要手动加载的DLL的依赖项,尝试去找到该依赖项所在的位置,然后再加载进来。详细代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyModel;
using Microsoft.Extensions.DependencyModel.Resolution;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using ZRB.Blog.Configurations;

namespace ZRB.Blog.Injection
{
public static class AssemblyLoader
{
private static readonly ICompilationAssemblyResolver AssemblyResolver;
private static readonly ConcurrentDictionary<string, CompilationLibrary> DependencyDLL;

static AssemblyLoader()
{
AssemblyLoadContext.Default.Resolving += Default_Resolving;
AssemblyResolver = new CompositeCompilationAssemblyResolver(
new ICompilationAssemblyResolver[]{
new AppBaseCompilationAssemblyResolver(AppDomain.CurrentDomain.BaseDirectory),
new ReferenceAssemblyPathResolver(),
new PackageCompilationAssemblyResolver()
});
DependencyDLL = new ConcurrentDictionary<string, CompilationLibrary>();
}

private static Assembly Default_Resolving(AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName)
{
if(DependencyDLL.ContainsKey(assemblyName.Name))
{
var compilationLibrary = DependencyDLL[assemblyName.Name];
var assemblies = new List<string>();
if (AssemblyResolver.TryResolveAssemblyPaths(compilationLibrary, assemblies) && assemblies.Count > 0)
{
var assembly = assemblyLoadContext.LoadFromAssemblyPath(assemblies[0]);
FindDependency(assembly);
return assembly;
}
}
return null;

}

public static Assembly GetAssembly(string assemblyName)
{
string assemblyFileName = AppDomain.CurrentDomain.BaseDirectory + assemblyName + ".dll";
Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName?.Split(',')[0] == assemblyName) ?? AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyFileName);
FindDependency(assembly);
return assembly;
}

private static void FindDependency(Assembly assembly)
{
DependencyContext dependencyContext = DependencyContext.Load(assembly);
if(dependencyContext!= null)
{
foreach (var compilationLibrary in dependencyContext.CompileLibraries)
{
if (!DependencyDLL.ContainsKey(compilationLibrary.Name)
&& !AppDomain.CurrentDomain.GetAssemblies().Any(a => a.FullName.Split(',')[0] == compilationLibrary.Name))
{
RuntimeLibrary library = dependencyContext.RuntimeLibraries.FirstOrDefault(runtime => runtime.Name == compilationLibrary.Name);
var cb = new CompilationLibrary(
library.Type,
library.Name,
library.Version,
library.Hash,
library.RuntimeAssemblyGroups.SelectMany(g => g.AssetPaths),
library.Dependencies,
library.Serviceable);

DependencyDLL[library.Name] = cb;
}
}
}
}
}
}