Loading Multiple Versions of the Same Assembly

Avoiding Loading Multiple Versions of an Assembly into the Same Context

A couple of different low-impact options to consider:

1) At application startup, copy customer assemblies only into main folder (we require our customer assemblies to have a specific naming convention in order to be loaded, so this is easy for us to implement).

2) At application startup, delete any copies of the standard DLLs in the customer directories to prevent conflicts.

C# Load different versions of assembly to the same project

The CLR does support loading multiple versions of strongly named assemblies into the same AppDomain. This only works though if your assemblies are strongly named and each one has a different version than the other.

I'm guessing it's more likely that you are dealing with unsigned assemblies. If that is the case then what you're asking for isn't really possible. Once a given assembly is loaded into an AppDomain it will remain there until the AppDomain is unloaded. To get this to work you will have to abstract out all of the work around the loaded assemblies into a separate AppDomain and use a new AppDomain for every assembly

PowerShell: why am I able to load multiple versions of the same .NET assembly in one session and also bypass Dependency hell?

In your scenario, your modules are stand-alone .NET assemblies that implement PowerShell cmdlets.

In both Windows PowerShell and PowerShell (Core) 7+, all assemblies are loaded into the same:

  • application domain in Windows PowerShell, which is based on .NET Framework.

  • ALC (assembly-load context) in PowerShell (Core) 7+, which is based on .NET Core / .NET 5+.

By default, loading multiple version of the same assembly is not supported, and the first one that is loaded into the session wins.

Subsequent attempts to load a different version of the assembly:

  • are quietly ignored in Windows PowerShell - irrespective of whether you use Import-Module, Add-Type -LiteralPath or its underlying .NET API method, [System.Reflection.Assembly]::LoadFrom() (be sure to pass a full file path to the latter, because PowerShell's working dir. usually differs from .NET's; the method outputs an object representing the assembly ostensibly just loaded, but it it actually represents the originally loaded version).

  • cause a statement-terminating error in Powershell (Core) 7+

    Assembly with same name is already loaded.

Note: You can load an assembly with a different version, namely via the [System.Reflection.Assembly]::LoadFile() method (note the File instead of From), but the only way you can use its types is via reflection.


From what I can tell:

  • There is no solution for cmdlet-implementing assemblies, as in your case.

    • By cmdlet-implementing I mean that the module's cmdlets are themselves implemented as .NET classes stored in an assembly, as opposed to cmdlets implemented in PowerShell code, in *.psm1 script-module files.

    • Whichever version of the cmdlet-implementing assembly you happen to import / load first in your session is the only one available in the remainder of the session; assemblies, once loaded, cannot be unloaded.

    • Another way of putting it: while you can have side-by-side versions of such modules on disk, you cannot load them simultaneously into a session, from what I can tell - this only works with script-based modules (see next point).

  • There are - nontrivial - solutions for loading multiple versions of helper assemblies into the same session; these are detailed in Resolving PowerShell module assembly dependency conflicts, which also provided extensive background information.

    • That is, if your cmdlets are implemented in PowerShell code and that code only uses auxiliary .NET assemblies, the linked documentation offers solutions for loading versions of these assemblies that would by default clash with different versions loaded by other modules or different versions of the same module.

How to reference and use multiple versions of same assembly in dotnet console application?

So this is how i went about with the change. I created a folder 'libs' under which i have 2 folders v40 and v43 and i have put the dlls 1 to 4 in v43 and the rest in v40 and then when my class is called, i load the dll dynamically. I also made sure that 'Copy always' is set so that dlls are always moved to the folder during build.

Now when i hit the client constructor that will be using v40 dll, i load the assembly path and then create an instance of main_40

    protected const string mxMainDLLPath = @"libs\v40\Main_40.dll";
dynamic mainObj = null;
public ClientClass()
{
Assembly assembly = Assembly.LoadFrom(mxMainDLLPath );
Type T = assembly.GetType("Main_40.Export");
mainObj = Activator.CreateInstance(T);
}

Now to call any method in Main_40.dll, i can do mainObj.Export().

Thanks to @NightOwl888 for all the help.



Related Topics



Leave a reply



Submit