Last active
March 23, 2018 19:45
-
-
Save Tornhoof/0124bb4b01484412efa221550972973c to your computer and use it in GitHub Desktop.
AssemblyLoadContext and Nuget
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Loader | |
{ | |
public static string ApplicationPath => AppDomain.CurrentDomain.BaseDirectory; | |
public const string ValidLibraryName = "MyLibs"; | |
public static IEnumerable<Assembly> MatchingAssemblies => | |
AppDomain.CurrentDomain.GetAssemblies().Where(x => IsValidLibrary(x.FullName)); | |
public static Type[] Types { get; } = GetAllTypesInternal(); | |
private static Type[] GetAllTypesInternal() | |
{ | |
LoadAllMatchingLibraries(); | |
return MatchingAssemblies.SelectMany(t => t.GetTypes().Where(x => x.IsPublic)).Distinct().ToArray(); | |
} | |
private static bool IsValidLibrary(string assemblyFullName) | |
{ | |
return Regex.IsMatch(assemblyFullName, ValidLibraryName); // only load the right ones | |
} | |
/// <summary> | |
/// Improve: https://github.com/dotnet/coreclr/issues/17014 | |
/// </summary> | |
private static void LoadAllMatchingLibraries() | |
{ | |
var directoryPath = ApplicationPath; | |
var finished = new HashSet<string>(); | |
// 1. We load the compileTimeLibraries first | |
var context = DependencyContext.Default; | |
foreach (var compileLibrary in context.CompileLibraries) | |
{ | |
foreach (var compileLibraryAssembly in compileLibrary.Assemblies) | |
{ | |
var libName = Path.GetFileNameWithoutExtension(compileLibraryAssembly); | |
if (IsValidLibrary(compileLibraryAssembly) && !finished.Contains(libName)) | |
{ | |
var fullPath = Path.Combine(directoryPath, compileLibraryAssembly); | |
AssemblyLoadContext.Default.LoadFromAssemblyPath(fullPath); | |
finished.Add(libName); | |
} | |
} | |
} | |
// 2. Now we need to load all other ValidLibraries from the directory and possibly resolve dependencies | |
var remainingLibraries = new Queue<string>(Directory | |
.GetFiles(directoryPath, $"{ValidLibraryName}.*.dll") | |
.Where(s => !finished.Contains(Path.GetFileNameWithoutExtension(s)))); | |
var envValue = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); | |
while (remainingLibraries.Count > 0) | |
{ | |
var current = remainingLibraries.Dequeue(); | |
var libName = Path.GetFileNameWithoutExtension(current); | |
if (!finished.Contains(libName)) | |
{ | |
if (File.Exists(current)) | |
{ | |
var asm = AssemblyLoadContext.Default.LoadFromAssemblyPath(current); | |
finished.Add(libName); | |
if (asm != null) | |
{ | |
var depcontext = DependencyContext.Load(asm); | |
if (depcontext != null) | |
{ | |
foreach (var runtimeLibrary in depcontext.RuntimeLibraries) | |
{ | |
if (runtimeLibrary.Type == "package" | |
) // we only care about nuget packages, our main dlls are local anyway | |
{ | |
foreach (var runtimeAssemblyGroup in runtimeLibrary.RuntimeAssemblyGroups) | |
{ | |
foreach (var assetPath in runtimeAssemblyGroup.AssetPaths) | |
{ | |
string packageSource = | |
$".nuget/packages/{runtimeLibrary.Name}/{runtimeLibrary.Version}"; | |
var fullPath = Path.Combine(envValue, packageSource, assetPath) | |
.Replace("\\", "/"); | |
remainingLibraries.Enqueue(fullPath); | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment