| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
…emblyLoadContext` (#11088)
|
🎉v7.0.0-rc.3 has been released which incorporates this pull request.:tada: Handy links: |
Sorry, something went wrong.
|
This PR prevents PowerShell from finding types in assemblies loaded from memory using [System.Reflection.Assembly]::Load($bytes) This has worked in PowerShell 5.1, and PowerShell 7 up to rc2 but doesn't work in rc3. A workaround for PowerShell 7 rc3 is to use # $ms is a MemoryStream containing the assembly bytes above [System.Runtime.Loader.AssemblyLoadContext]::Default.LoadFromStream($ms) However the above code is not compatible with PowerShell 5.1 as the type doesn't exist. |
Sorry, something went wrong.
|
Are you able to expand on your scenario for using that API? I haven't seen any use cases in .NET Framework for loading an assembly from bytes other than to get around assembly resolution issues, which .NET Core has effectively resolved with the addition of assembly load contexts. Really this change is us catching up to deeper changes in .NET assembly handling, and given that these changes have occurred in the platform and something fundamentally different is happening (i.e. the loaded assembly really isn't in the current load context), it's probably appropriate to handle the loading differently on different platforms: if ($PSVersionTable.PSVersion.Major -ge 7)
{
$ms = ...
[System.Runtime.Loader.AssemblyLoadContext]::Default.LoadFromStream($ms)
}
else
{
[System.Reflection.Assembly]::Load($bytes)
} |
Sorry, something went wrong.
|
The core use case is when you don't want the DLL to be locked on the file system in Windows, preventing rebuilds/reinstalls etc. I typically load my more complex DLLs using add-type, but I have a native interop DLL that checks file locking status on startup and handles upgrading of assemblies and native DLLs by inspecting the install folder for locked files. I don't want loading this DLL to also cause file locking so I load it from memory - it has no external dependencies so this works fine. I used something like the above code, but I tested for the presence of the AssemblyLoadContext type, rather than tying it to the PSVersion. |
Sorry, something went wrong.
Yes, this is something an ALC can solve today, since they can be collectible/unloadable. Meaning the strategy for handling the problem will probably change significantly moving into the future. We've been discussing how best to support this going forward and there's no simple solution available by default in PowerShell yet, but it's certainly an area of interest. |
Sorry, something went wrong.
|
I don't think being able to unload from a specific PowerShell will solve my issue, which is users may have multiple PowerShell windows open, each of which would have locked the DLLs when they upgrade. I currently resolve it by checking for locked files and creating a new sequence number folder for the new version of DLLs on upgrade, which is what the in-memory DLL helps with. Most of my users are on PS 5.1 as well, but I'm on both. |
Sorry, something went wrong.
|
stevenebutler Please open new issue with repo steps.
It is not PowerShell, it is .Net Core method. You could create simple C# application and check with different .Net Core 3 versions. |
Sorry, something went wrong.
The preliminary issue is that PowerShell stopped resolving types outside the default ALC with the changes in this PR. However, Assembly.Load effectively made a breaking change first, since it loads byte assemblies into an anonymous ALC. Given that ALCs are designed partially to replace AppDomains, I think not resolving from them is the right way to go (and I should note that fully qualified names still work). |
Sorry, something went wrong.
|
Rob Holt (@rjmholt) Thanks! In the case I see another additional problem https://source.dot.net/#System.Private.CoreLib/Assembly.cs,242 |
Sorry, something went wrong.
|
I'm not sure I want to create an issue for this as I understand this area is changing and PowerShell has to adapt. It's obviously a change in behaviour that may break existing code, so I wanted to let people know how they could adapt. I am happy with the change I have made and don't have any issues with it now. In case anyone does feel strongly about this and wants to raise an issue with a repro, the below pester test will repro the issue (fail) on PowerShell 7.0.0 rc3 (and release), but will pass on versions prior. For completeness, I have included a second test that shows how to load types from memory in PowerShell, which passes on PowerShell 7.0.0rc3 and above.. import-module Pester
Describe "PowerShell C# type visibility" {
It "[Assembly]::Load(`$bytes) types are visible to PowerShell" {
$testdll = "$env:TEMP/visibility.dll"
if (test-path $testdll) {
remove-item $testdll -force
}
Add-Type @"
public class Visibility {
public static string Test = "Found";
}
"@ -Language CSharp -OutputAssembly $testdll
$bytes = [System.IO.File]::ReadAllBytes($testdll)
[System.Reflection.Assembly]::Load($bytes)
[Visibility]::Test | should be "Found"
}
It "System.Runtime.Loader.AssemblyLoadContext]::Default.LoadFromStream(`$memoryStream) types are visible to PowerShell" {
$testdll = "$env:TEMP/visibility2.dll"
if (test-path $testdll) {
remove-item $testdll -force
}
Add-Type @"
public class Visibility2 {
public static string Test = "Found";
}
"@ -Language CSharp -OutputAssembly $testdll
$bytes = [System.IO.File]::ReadAllBytes($testdll)
$ms = new-object System.IO.MemoryStream
try {
$ms.Write($bytes, 0, $bytes.Length)
$ms.Seek(0, [System.IO.SeekOrigin]::Begin)
# This will fail on Windows PowerShell 5.1
[System.Runtime.Loader.AssemblyLoadContext]::Default.LoadFromStream($ms)
}
finally {
$ms.Dispose()
}
[Visibility2]::Test | should be "Found"
}
}Output on 7.0.0 rc3: Describing PowerShell C# type visibilty [-] [Assembly]::Load($bytes) types are visible to PowerShell 119ms RuntimeException: Unable to find type [Visibility]. at <ScriptBlock>, C:\dev\repro-AssemblyLoad.ps1: line 18 [+] System.Runtime.Loader.AssemblyLoadContext]::Default.LoadFromStream($memoryStream) types are visible to PowerShell 147ms |
Sorry, something went wrong.
|
stevenebutler In cast you don't know yet, #12052 is tracking the issue you reported, and the PR #12203 was submitted to fix it. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
PR Summary
In .NET Core 2.1, [System.AppDomain]::CurrentDomain.GetAssemblies() only returns the assemblies loaded in the default load context.
In .NET Core 3.0, [System.AppDomain]::CurrentDomain.GetAssemblies() is changed to return all assemblies loaded in the AppDomain, including the assemblies loaded into other AssemblyLoadContext (ALC) instances.
This results in our type resolution to behave inconsistently:
This PR changes to use AssemblyLoadContext.Default.Assemblies (new API added in .NET Core 3) to make sure assemblies loaded in other ALC are invisible to PowerShell type resolution.
PR Context
PR Checklist