68 lines
3.0 KiB
C#
68 lines
3.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Runtime.Loader;
|
|
using Prise.Utils;
|
|
|
|
namespace Prise.AssemblyScanning
|
|
{
|
|
/// <summary>
|
|
/// This class is not tested
|
|
/// </summary>
|
|
public class DefaultAssemblyResolver : MetadataAssemblyResolver
|
|
{
|
|
private readonly string assemblyPath;
|
|
private readonly string[] platformAssemblies = new[] { "mscorlib", "netstandard", "System.Private.CoreLib", "System.Runtime" };
|
|
|
|
public DefaultAssemblyResolver(string fullPathToAssembly)
|
|
{
|
|
this.assemblyPath = Path.GetDirectoryName(fullPathToAssembly.ThrowIfNullOrEmpty(nameof(fullPathToAssembly)));
|
|
}
|
|
|
|
public override Assembly Resolve(MetadataLoadContext context, AssemblyName assemblyName)
|
|
{
|
|
// We know these assemblies are located in the Host, so don't bother loading them from the plugin location
|
|
if (this.platformAssemblies.Contains(assemblyName.Name))
|
|
{
|
|
return LoadAssemblyForRuntime(context, assemblyName);
|
|
}
|
|
|
|
// Check if the file is found in the plugin location
|
|
var candidateFile = Path.Combine(assemblyPath, $"{assemblyName.Name}.dll");
|
|
if (File.Exists(candidateFile))
|
|
return context.LoadFromAssemblyPath(candidateFile);
|
|
|
|
// Fallback, load from Host AppDomain, this is mostly required for System.* assemblies
|
|
return LoadAssemblyForRuntime(context, assemblyName);
|
|
}
|
|
|
|
protected Assembly LoadAssemblyForRuntime(MetadataLoadContext context, AssemblyName assemblyName)
|
|
{
|
|
try
|
|
{
|
|
var candidate = GetLoadedAssemblies().FirstOrDefault(a => a.GetName().Name == assemblyName.Name);
|
|
var candidateName = candidate != null ? candidate.GetName() : null;
|
|
|
|
if (candidateName != null && candidateName.Version != assemblyName.Version)
|
|
{
|
|
return context.LoadFromAssemblyPath(AssemblyLoadContext.Default.LoadFromAssemblyName(candidateName).Location);
|
|
}
|
|
|
|
return context.LoadFromAssemblyPath(AssemblyLoadContext.Default.LoadFromAssemblyName(assemblyName).Location);
|
|
}
|
|
catch (FileNotFoundException) when (assemblyName?.Name == "System.Runtime")
|
|
{
|
|
var hostRuntimeAssembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
|
|
throw new AssemblyScanningException($"System.Runtime {assemblyName.Version} failed to load. Are you trying to load a new plugin into an old host? Host Runtime Version: {hostRuntimeAssembly.GetName().Version} on {hostRuntimeAssembly.CodeBase}");
|
|
}
|
|
}
|
|
|
|
#if SUPPORTS_LOADED_ASSEMBLIES
|
|
protected IEnumerable<Assembly> GetLoadedAssemblies() => AssemblyLoadContext.Default.Assemblies;
|
|
#else
|
|
protected IEnumerable<Assembly> GetLoadedAssemblies() => AppDomain.CurrentDomain.GetAssemblies();
|
|
#endif
|
|
}
|
|
} |