Skip to content

Instantly share code, notes, and snippets.

@Tornhoof
Last active March 23, 2018 19:45
Show Gist options
  • Save Tornhoof/0124bb4b01484412efa221550972973c to your computer and use it in GitHub Desktop.
Save Tornhoof/0124bb4b01484412efa221550972973c to your computer and use it in GitHub Desktop.
AssemblyLoadContext and Nuget
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