1

Script evaluation code snippet:

        using (var loader = new InteractiveAssemblyLoader())
        {
            var script = CSharpScript.Create<TDataType>(
           code: expr,
           options: ScriptOptions.Default.AddImports(globals.GetType().Namespace)
                                         .AddReferences(refAssemblies),
           globalsType: globals.GetType(),
           assemblyLoader: loader);

            return script.RunAsync(globals).Result.ReturnValue;
        }

The code-analysis assemblies and the globals-type assembly are loaded into the same Collectible AssemblyLoadContext... Also tried adding references/imports explicitly through the ScriptOptions but get the same following error:

Inner Exception 1: InvalidCastException: [A]TestLibrary.TestClass cannot be cast to [B]TestLibrary.TestClass. Type A originates from 'TestLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location '...\TestLibrary.dll'. Type B originates from 'TestLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' in the context 'Default' at location '...\TestLibrary.dll'.

rn3
  • 11
  • 1

1 Answers1

0

It seems the assembly loader is loading twice TestLibrary in your dynamic code, you can avoid that resolving manually the assembly (beware that TestLibrary must be the same version in both projects)

//Somewhere in your startup code:
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler);

static Assembly MyResolveEventHandler(object sender, AssemblyLoadEventArgs args)         
{
    //First time it will be null and the resolver will load it from the default path, the succesive requests to load the library will return the already loaded assembly.
    if(args.Name == "TestLibrary")
        return AppDomain.CurrentDomain.GetAssemblies().Where(a => a.Name == args.Name).FirstOrDefault(); 

    return null;
}
Gusman
  • 14,905
  • 2
  • 34
  • 50
  • `FirstOrDefault` can take a predicate: `AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.Name == args.Name)` – Paulo Morgado Jun 13 '20 at 20:20
  • In my case the same assembly is loaded into 2 different load contexts...but thank you for this solution...maybe I can adapt this to check the custom load context and prevent the loading of the the dll into default load context again... – rn3 Jun 15 '20 at 17:08
  • This does not work since the AssemblyResolve event is not fired in my case, maybe because the system resolved it and loaded the assembly into the default load context... – rn3 Jun 15 '20 at 17:33
  • @m3 If you are using an `AssemblyLoadContext` to load libraries then you can hook to the `Resolving` event of the context and do the same as in my example, return the one on the domain assemblies. – Gusman Jun 15 '20 at 18:02
  • Resolving will fire only if the load fails but in this case the load into 'Default' context succeeds but we want to prevent that load since the assembly is loaded already into another context... – rn3 Jun 16 '20 at 17:18
  • opened an issue on CSharpScript Github [link](https://github.com/dotnet/roslyn/issues/45197) – rn3 Jun 17 '20 at 22:05
  • Update - Roslyn team has tagged this issue as a bug... – rn3 Jun 22 '20 at 16:56