mercredi 24 juillet 2019

How can I load "assembly extern" references using AssemblyLoadContext?

I am building a simple plugin architecture in .NET Core 3.0. I have a solution with two projects: Plugin and WpfApp. Here is the version of the .NET Core 3.0 SDK I have installed:

PS > dotnet --version
3.0.100-preview7-012821

Plugin

The Plugin project is a class library project targeting .NET Standard 2.0. It references the System.Management NuGet package version 4.5.0 and uses classes from that package. The project compiles, of course. Here is the relevant IL from the assembly showing the assembly extern reference:

// Metadata version: v4.0.30319
.assembly extern netstandard
{
  .publickeytoken = (CC 7B 13 FF CD 2D DD 51 )                         // .{...-.Q
  .ver 2:0:0:0
}
.assembly extern System.Management
{
  .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A )                         // .?_....:
  .ver 4:0:0:0
}

WpfApp

The WpfApp project is a WPF project targeting .NET Core 3.0. I configured the project to depend on Plugin using Solution Explorer's Project Dependencies feature, since WpfApp doesn't directly reference Plugin. This ensures Plugin always builds before WpfApp.

WpfApp references the System.Runtime.Loader NuGet package version 4.3.0 in order to use its AssemblyLoadContext class. My MainWindow window loads the Plugin project DLL using AssemblyLoadContext.LoadAssemblyFromFile. WpfApp then instantiates a MyPlugin class from Plugin and attempts to invoke the Invoke method. Invoke instantiates classes from System.Management:

Assembly assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(@"C:\Solutions\Plugins\Plugin\bin\Debug\netstandard2.0\Plugin.dll");
object instance = assembly.CreateInstance("Plugin.MyPlugin");

instance.GetType().GetMethod("Invoke").Invoke(instance, new object[0]);

As soon as Invoke attempts to do this, an exception is thrown:

System.Reflection.TargetInvocationException: 'Exception has been thrown by the target of an invocation.'

Inner exception:

FileNotFoundException: Could not load file or assembly 'System.Management, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.

What's going on here?

I expected AssemblyLoadContext to load all these system references, but it seems I was incorrect. As far as I can tell, referencing the NuGet package does not actually copy DLLs to Plugin's output directory but merely causes the above assembly extern IL to be generated. This is breaking my plugin architecture because I cannot possibly know all the external .NET Core 3.0 SDK assemblies that all plugins might reference. I'd understand if it were trying to load third-party references but these are NuGet packages representing DLLs included in the .NET Core 3.0 SDK. In my case, I can guarantee they'll be on the system.

Am I doing something wrong? How can I get AssemblyLoadContext to load these external references? Alternatively, is there any other way of getting this to work aside from copying System.Management.dll (which I do not view as a viable solution)?





Aucun commentaire:

Enregistrer un commentaire