用的net core版本是2.1,也許在后續的版本中已經修復了這個問題
今天在嘗試用net core寫demo的時候,發現了這個問題。因為都是使用DI,所以就沒有我的網站項目里直接引用一些實現類庫,而是放到了同一個目錄下,在網站啟動的時候用代碼去加載進來。然而在實際的運行過程成中發現,指定的dll會自動加載,但是其依賴的nuget包里的dll不會被加載進來,在Google了很久,也發現了很多人提出過這個問題,在GitHub上也有人提過https://github.com/dotnet/corefx/issues/21982,但是都沒有直接的解決方案,其中有一個差不多的解決方案https://www.codeproject.com/Articles/1194332/Resolving-Assemblies-in-NET-Core,我的解決方案也是依據這個改進而來的。
代碼的核心思路是去找需要手動加載的DLL的依賴項,嘗試去找到該依賴項所在的位置,然后再加載進來。詳細代碼如下:
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; } } } } } }