cloudbase / powershell-yaml

PowerShell CmdLets for YAML format manipulation
Apache License 2.0
434 stars 78 forks source link

mscorlib is not referenced #121

Closed abbgrade closed 3 months ago

abbgrade commented 9 months ago

Hello,

First of all: Thank you for this module.

When I import platyPS, before I load powershell-yaml, I get the following issue:

(7,36): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. public class StringQuotingEmitter: ChainedEventEmitter {

If I load powershell-yaml before platyPS, the import of platyPS I get:

Assembly with same name is already loaded

I found out, that both modules use YamlDotNet.dll but in different versions. Both outdated, but this is not the issue. I think, there are patterns to solve this: https://github.com/jborean93/PowerShell-ALC contains an example.

gabriel-samfira commented 9 months ago

sigh

Yes. We'll probably go with load contexts in the end. When we created the module, we wanted to allow users to not use the bundled assembly, provided they go for a newer version or use their own. This was done mostly because on some organizations, opaque binary blobs are frowned upon. So we check if the assembly is loaded and only load it if it doesn't exist. But as you and others have come to notice, it sometimes bites back.

I will allocate some time to make the needed changes. Will ping back here when I have something.

abbgrade commented 9 months ago

thanks a lot. I feed you pain. I have the same task for a few modules, I maintain.

splatteredbits commented 3 months ago

Steps to reproduce this error:

  1. Download version 11.2.1 of YamlDotNet.dll targeting netstandard.dll.
  2. In Windows PowerShell 5.1 on .NET Framework 4.8:
    1. Add-Type -Path path\to\above\YamlDotNet.dll
    2. Import-Module .\powershell-yaml
    3. Note the error.

If you supply any value to the Add-Type function's ReferenceAssemblies parameter, Add-Type in Windows PowerShell only references those types; it doesn't include any core assemblies.

gabriel-samfira commented 3 months ago

Hi folks, could you give https://github.com/cloudbase/powershell-yaml/pull/132 a try? It should fix the conflict.

gabriel-samfira commented 3 months ago

short demo:

# import platyps first
gabriel@rossak:~/powershell-yaml$ pwsh
PowerShell 7.4.5
PS /home/gabriel/powershell-yaml> import-module platyps
PS /home/gabriel/powershell-yaml> import-module ./powershell-yaml.psd1                   
PS /home/gabriel/powershell-yaml> exit

# import powershell-yaml first
gabriel@rossak:~/powershell-yaml$ pwsh
PowerShell 7.4.5
PS /home/gabriel/powershell-yaml> import-module ./powershell-yaml.psd1                   
PS /home/gabriel/powershell-yaml> import-module platyps               

List all ALCs:

PS /home/gabriel/powershell-yaml> [System.Runtime.Loader.AssemblyLoadContext]::All | fl *

Assemblies    : {System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, pwsh, Version=7.4.5.500, Culture=neutral, PublicKeyToken=31bf3856ad364e35, 
                System.Runtime, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, System.Management.Automation, Version=7.4.5.500, Culture=neutral, 
                PublicKeyToken=31bf3856ad364e35…}
IsCollectible : False
Name          : Default

Assemblies    : {YamlDotNet, Version=13.0.0.0, Culture=neutral, PublicKeyToken=ec19458f3c15af5e, jbtx4qo5.tda, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null}
IsCollectible : True
Name          : powershellyaml

And the assemblies from both ALCs:

PS /home/gabriel/powershell-yaml> import-module platyps                                                                
PS /home/gabriel/powershell-yaml> import-module ./powershell-yaml.psd1
PS /home/gabriel/powershell-yaml> $gac = ([System.Runtime.Loader.AssemblyLoadContext]::All | ? {$_.Name -eq 'Default'})
PS /home/gabriel/powershell-yaml> $pwshY = ([System.Runtime.Loader.AssemblyLoadContext]::All | ? {$_.Name -eq 'powershellyaml'})
PS /home/gabriel/powershell-yaml> $pwshY.Assemblies | ? {$_.Location -like "*YamlDotNet.dll" }                                  

GAC    Version        Location
---    -------        --------
False  v4.0.30319     /home/gabriel/powershell-yaml/lib/netstandard2.1/YamlDotNet.dll

PS /home/gabriel/powershell-yaml> $gac.Assemblies | ? {$_.Location -like "*YamlDotNet.dll" }                                    

GAC    Version        Location
---    -------        --------
False  v4.0.30319     /home/gabriel/.local/share/powershell/Modules/platyPS/0.14.2/YamlDotNet.dll
gabriel-samfira commented 3 months ago

Given that powershell-yaml is written in powershell and not C#, this approach in using ALC may look strange, but it allows us to load assemblies in a different context (on powershell 6+) and use the types from the assemblies in that context. It's not the usual way to use ALC, but it seems to work for the dependencies we need.

On powershell < 6 we still use the GAC.