diff --git a/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs b/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/PowerShellAssemblyLoader.cs
similarity index 92%
rename from src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs
rename to src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/PowerShellAssemblyLoader.cs
index cb2cc44d8e..418ec2b8a3 100644
--- a/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs
+++ b/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/PowerShellAssemblyLoader.cs
@@ -15,14 +15,14 @@ using System.Runtime.Loader;
namespace System.Management.Automation
{
///
- /// The powershell custom AssemblyLoadContext implementation
+ /// The powershell custom assembly loader implementation
///
- internal partial class PowerShellAssemblyLoadContext : AssemblyLoadContext
+ internal partial class PowerShellAssemblyLoader
{
#region Resource_Strings
// We cannot use a satellite resources.dll to store resource strings for Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll. This is because when retrieving resource strings, ResourceManager
- // tries to load the satellite resources.dll using a probing approach, which will cause an infinite loop to PowerShellAssemblyLoadContext.Load(AssemblyName).
+ // tries to load the satellite resources.dll using a probing approach, which will cause an infinite loop to PowerShellAssemblyLoader.Load(AssemblyName).
// Take the 'en-US' culture as an example. When retrieving resource string to construct an exception, ResourceManager calls Assembly.Load(..) in the following order to load the resource dll:
// 1. Load assembly with culture 'en-US' (Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.resources, Version=3.0.0.0, Culture=en-US, PublicKeyToken=31bf3856ad364e35)
// 2. Load assembly with culture 'en' (Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.resources, Version=3.0.0.0, Culture=en, PublicKeyToken=31bf3856ad364e35)
@@ -37,13 +37,6 @@ namespace System.Management.Automation
#region Constructor
- ///
- /// This constructor is for testability purpose only
- ///
- protected PowerShellAssemblyLoadContext()
- {
- }
-
///
/// Constructor
///
@@ -51,7 +44,7 @@ namespace System.Management.Automation
/// Base directory paths that are separated by semicolon ';'.
/// They will be the default paths to probe assemblies.
///
- internal PowerShellAssemblyLoadContext(string basePaths)
+ internal PowerShellAssemblyLoader(string basePaths)
{
#region Validation
this.basePaths = basePaths.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
@@ -77,12 +70,18 @@ namespace System.Management.Automation
// - Key: namespace qualified type name (FullName)
// - Value: strong name of the TPA that contains the type represented by Key.
coreClrTypeCatalog = InitializeTypeCatalog();
+
+ this.loadContext = AssemblyLoadContext.Default;
+ loadContext.Resolving += Resolve;
}
#endregion Constructor
#region Fields
+ // AssemblyLoadContext used by this loader
+ private readonly AssemblyLoadContext loadContext;
+
// Serialized type catalog file
private readonly object syncObj = new object();
private readonly string[] basePaths;
@@ -118,10 +117,15 @@ namespace System.Management.Automation
#region Protected_Internal_Methods
///
- /// Implement the AssemblyLoadContext.Load(AssemblyName). Search the requested assembly in probing paths.
+ /// The global instance of PowerShellAssemblyLoader
+ ///
+ internal static PowerShellAssemblyLoader Instance { get; set; }
+
+ ///
+ /// Implement the AssemblyLoadContext.Resolving event handler. Search the requested assembly in probing paths.
/// Search the file "[assemblyName.Name][.ni].dll" in probing paths. If the file is found and it matches the requested AssemblyName, load it with LoadFromAssemblyPath.
///
- protected override Assembly Load(AssemblyName assemblyName)
+ internal Assembly Resolve(AssemblyLoadContext sender, AssemblyName assemblyName)
{
// Probe the assembly cache
Assembly asmLoaded;
@@ -153,7 +157,7 @@ namespace System.Management.Automation
if (File.Exists(asmFilePath))
{
isAssemblyFileFound = true;
- AssemblyName asmNameFound = GetAssemblyName(asmFilePath);
+ AssemblyName asmNameFound = AssemblyLoadContext.GetAssemblyName(asmFilePath);
if (IsAssemblyMatching(assemblyName, asmNameFound))
{
isAssemblyFileMatching = true;
@@ -187,8 +191,8 @@ namespace System.Management.Automation
try
{
asmLoaded = asmFilePath.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase)
- ? LoadFromNativeImagePath(asmFilePath, null)
- : LoadFromAssemblyPath(asmFilePath);
+ ? loadContext.LoadFromNativeImagePath(asmFilePath, null)
+ : loadContext.LoadFromAssemblyPath(asmFilePath);
}
// Since .NET CLI built versions of PowerShell have all the
// built-in assemblies in the TPA list, the above will throw,
@@ -211,6 +215,14 @@ namespace System.Management.Automation
return asmLoaded;
}
+ ///
+ /// Load an assembly from its name.
+ ///
+ internal Assembly LoadFromAssemblyName(AssemblyName assemblyName)
+ {
+ return loadContext.LoadFromAssemblyName(assemblyName);
+ }
+
///
/// Load an assembly from its file path.
///
@@ -239,7 +251,7 @@ namespace System.Management.Automation
#endregion Validation
Assembly asmLoaded;
- AssemblyName assemblyName = GetAssemblyName(assemblyPath);
+ AssemblyName assemblyName = AssemblyLoadContext.GetAssemblyName(assemblyPath);
// Probe the assembly cache
if (TryGetAssemblyFromCache(assemblyName, out asmLoaded))
@@ -256,8 +268,8 @@ namespace System.Management.Automation
{
// Load the assembly through 'LoadFromNativeImagePath' or 'LoadFromAssemblyPath'
asmLoaded = assemblyPath.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase)
- ? LoadFromNativeImagePath(assemblyPath, null)
- : LoadFromAssemblyPath(assemblyPath);
+ ? loadContext.LoadFromNativeImagePath(assemblyPath, null)
+ : loadContext.LoadFromAssemblyPath(assemblyPath);
}
// Since .NET CLI built versions of PowerShell have all the
// built-in assemblies in the TPA list, the above will throw,
@@ -290,7 +302,7 @@ namespace System.Management.Automation
///
internal Assembly LoadFrom(Stream assembly)
{
- var asm = LoadFromStream(assembly);
+ var asm = loadContext.LoadFromStream(assembly);
TryAddAssemblyToCache(asm);
return asm;
}
@@ -498,13 +510,11 @@ namespace System.Management.Automation
}
///
- /// Set an instance of PowerShellAssemblyLoadContext to be the default Assembly Load Context.
+ /// Set an instance of PowerShellAssemblyLoader to be the default Assembly Load Context.
/// This is the managed entry point for Microsoft.PowerShell.CoreCLR.AssemblyLoadContext.dll.
///
public class PowerShellAssemblyLoadContextInitializer
{
- private static bool IsInitialized = false;
-
// Porting note: it's much easier to send an LPStr on Linux
private const UnmanagedType stringType =
#if LINUX
@@ -519,19 +529,9 @@ namespace System.Management.Automation
///
public static void SetPowerShellAssemblyLoadContext([MarshalAs(stringType)]string basePaths)
{
- if (!IsInitialized)
+ if (PowerShellAssemblyLoader.Instance == null)
{
- var psAsmLoadContext = new PowerShellAssemblyLoadContext(basePaths);
- try
- {
- AssemblyLoadContext.InitializeDefaultContext(psAsmLoadContext);
- }
- catch (System.InvalidOperationException)
- {
- // We may not be able to set the default context. If we're under the
- // xUnit test harness, it has already been set.
- }
- IsInitialized = true;
+ PowerShellAssemblyLoader.Instance = new PowerShellAssemblyLoader(basePaths);
}
}
}
diff --git a/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CorePsTypeCatalog.cs b/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CorePsTypeCatalog.cs
index d00fa92ccf..7a5acf16f1 100644
--- a/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CorePsTypeCatalog.cs
+++ b/src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CorePsTypeCatalog.cs
@@ -10,7 +10,7 @@ using System.Collections.Generic;
namespace System.Management.Automation
{
- internal partial class PowerShellAssemblyLoadContext
+ internal partial class PowerShellAssemblyLoader
{
private Dictionary InitializeTypeCatalog()
{
diff --git a/src/System.Management.Automation/resources/ParserStrings.resx b/src/System.Management.Automation/resources/ParserStrings.resx
index ba99c3d0da..807450a9d7 100644
--- a/src/System.Management.Automation/resources/ParserStrings.resx
+++ b/src/System.Management.Automation/resources/ParserStrings.resx
@@ -1352,7 +1352,7 @@ ModuleVersion : Version of module to import. If used, ModuleName must represent
Cannot run a document in PowerShell Core: {0}.
- The default AssemblyLoadContext in use is invalid. The default AssemblyLoadContext for PowerShell Core should be of type 'PowerShellAssemblyLoadContext'.
+ The default AssemblyLoadContext in use is invalid. The default AssemblyLoadContext for PowerShell Core should be of type 'PowerShellAssemblyLoader'.
Multiple type constraints are not allowed on a method parameter.
diff --git a/src/System.Management.Automation/utils/ClrFacade.cs b/src/System.Management.Automation/utils/ClrFacade.cs
index edb4de9d64..744e2bb5e2 100644
--- a/src/System.Management.Automation/utils/ClrFacade.cs
+++ b/src/System.Management.Automation/utils/ClrFacade.cs
@@ -276,7 +276,7 @@ namespace System.Management.Automation
internal static IEnumerable GetAssemblies(string namespaceQualifiedTypeName = null)
{
#if CORECLR
- var psAssemblyLoader = GetAssemblyLoadContext();
+ var psAssemblyLoader = GetAssemblyLoader();
return psAssemblyLoader.GetAssemblies(namespaceQualifiedTypeName);
#else
return AppDomain.CurrentDomain.GetAssemblies().Where(a => !(a.FullName.Length > 0 && a.FullName[0] == FIRST_CHAR_PSASSEMBLY_MARK));
@@ -290,7 +290,7 @@ namespace System.Management.Automation
internal static Assembly LoadFrom(string assemblyPath)
{
#if CORECLR
- var psAssemblyLoader = GetAssemblyLoadContext();
+ var psAssemblyLoader = GetAssemblyLoader();
return psAssemblyLoader.LoadFrom(assemblyPath);
#else
return Assembly.LoadFrom(assemblyPath);
@@ -303,7 +303,7 @@ namespace System.Management.Automation
///
internal static Assembly LoadFrom(Stream assembly)
{
- var psAssemblyLoader = GetAssemblyLoadContext();
+ var psAssemblyLoader = GetAssemblyLoader();
return psAssemblyLoader.LoadFrom(assembly);
}
#endif
@@ -315,7 +315,7 @@ namespace System.Management.Automation
internal static Assembly Load(AssemblyName assembly)
{
#if CORECLR
- var psAssemblyLoader = GetAssemblyLoadContext();
+ var psAssemblyLoader = GetAssemblyLoader();
return psAssemblyLoader.LoadFromAssemblyName(assembly);
#else
return Assembly.Load(assembly);
@@ -328,7 +328,7 @@ namespace System.Management.Automation
internal static Assembly Load(string assembly)
{
#if CORECLR
- var psAssemblyLoader = GetAssemblyLoadContext();
+ var psAssemblyLoader = GetAssemblyLoader();
return psAssemblyLoader.LoadFromAssemblyName(new AssemblyName(assembly));
#else
return Assembly.Load(assembly);
@@ -347,7 +347,7 @@ namespace System.Management.Automation
#if CORECLR
// Create the enum type and add the dynamic assembly to assembly cache.
TypeInfo enumTypeinfo = enumBuilder.CreateTypeInfo();
- var psAssemblyLoader = GetAssemblyLoadContext();
+ var psAssemblyLoader = GetAssemblyLoader();
psAssemblyLoader.TryAddAssemblyToCache(enumTypeinfo.Assembly);
#else
enumBuilder.CreateTypeInfo();
@@ -370,7 +370,7 @@ namespace System.Management.Automation
throw new ArgumentNullException("assemblyShortName");
}
- var psAssemblyLoader = GetAssemblyLoadContext();
+ var psAssemblyLoader = GetAssemblyLoader();
return psAssemblyLoader.ProbeAssemblyFileForMetadataAnalysis(assemblyShortName, additionalSearchPath);
}
@@ -380,28 +380,22 @@ namespace System.Management.Automation
///
internal static IEnumerable GetAvailableCoreClrDotNetTypes()
{
- var psAssemblyLoader = GetAssemblyLoadContext();
+ var psAssemblyLoader = GetAssemblyLoader();
return psAssemblyLoader.GetAvailableDotNetTypes();
}
///
/// Get the powershell custom AssemblyLoadContext.
///
- internal static PowerShellAssemblyLoadContext GetAssemblyLoadContext()
+ internal static PowerShellAssemblyLoader GetAssemblyLoader()
{
if (_psLoadContext == null)
{
- _psLoadContext = AssemblyLoadContext.Default as PowerShellAssemblyLoadContext;
- if (_psLoadContext == null)
- {
- // The default load context may not be ours. This can happen during,
- // for instance, xUnit testing.
- _psLoadContext = new PowerShellAssemblyLoadContext(String.Empty);
- }
+ _psLoadContext = PowerShellAssemblyLoader.Instance;
}
return _psLoadContext;
}
- private static volatile PowerShellAssemblyLoadContext _psLoadContext;
+ private static volatile PowerShellAssemblyLoader _psLoadContext;
#endif
///
diff --git a/src/TypeCatalogGen/TypeCatalogGen.cs b/src/TypeCatalogGen/TypeCatalogGen.cs
index ecaff01c02..5aa7a44f4a 100644
--- a/src/TypeCatalogGen/TypeCatalogGen.cs
+++ b/src/TypeCatalogGen/TypeCatalogGen.cs
@@ -41,7 +41,7 @@ Usage: TypeCatalogGen.exe <{0}> <{1}>
/*
* Go through all reference assemblies of .NET Core and generate the type catalog -> Dictionary
- * Then auto-generate the partial class 'PowerShellAssemblyLoadContext' that has the code to initialize the type catalog cache.
+ * Then auto-generate the partial class 'PowerShellAssemblyLoader' that has the code to initialize the type catalog cache.
*
* In CoreCLR, there is no way to get all loaded TPA assemblies (.NET Framework Assemblies). In order to get type based on type name, powershell needs to know what .NET
* types are available and in which TPA assemblies. So we have to generate the type catalog based on the reference assemblies of .NET Core.
@@ -105,7 +105,7 @@ Usage: TypeCatalogGen.exe <{0}> <{1}>
}
}
- WritePowerShellAssemblyLoadContextPartialClass(targetFilePath, typeNameToAssemblyMap);
+ WritePowerShellAssemblyLoaderPartialClass(targetFilePath, typeNameToAssemblyMap);
}
///
@@ -272,7 +272,7 @@ Usage: TypeCatalogGen.exe <{0}> <{1}>
///
/// Generate the CSharp source code that initialize the type catalog.
///
- private static void WritePowerShellAssemblyLoadContextPartialClass(string targetFilePath, Dictionary typeNameToAssemblyMap)
+ private static void WritePowerShellAssemblyLoaderPartialClass(string targetFilePath, Dictionary typeNameToAssemblyMap)
{
const string SourceFormat = " typeCatalog[\"{0}\"] = \"{1}\";";
const string SourceHead = @"//
@@ -287,7 +287,7 @@ using System.Collections.Generic;
namespace System.Management.Automation
{{
- internal partial class PowerShellAssemblyLoadContext
+ internal partial class PowerShellAssemblyLoader
{{
private Dictionary InitializeTypeCatalog()
{{