LoaderOptimization.MultiDomain causes AssemblyResolve to not fire

283 Views Asked by At

I have some issues as soon as LoaderOptimization.MultiDomainis enabled. Somehow, it doesn't fire AssemblyResolve event anymore when an assembly is not found in some specific scenarios.

I narrowed it down to a repro case with 2 projects. You can download full solution here: https://developercommunity.visualstudio.com/storage/attachments/24787-appdomainresolvetest.zip

Let's say I have a top level program:

class AppProgram
{
    // Comment this and both Resolve1 and Resolve2 will happen
    // If enabled, Resolve2 doesn't happen
    [LoaderOptimization(LoaderOptimization.MultiDomain)]
    static void Main(string[] args)
    {
        var applicationPath = AppDomain.CurrentDomain.BaseDirectory;

        var appDomainSetup = new AppDomainSetup { ApplicationBase = Directory.GetParent(applicationPath).FullName };
        var otherDomain = AppDomain.CreateDomain("other domain", AppDomain.CurrentDomain.Evidence, appDomainSetup);
        otherDomain.DoCallBack(TestCallback);
    }

    private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        Console.WriteLine($"Resolve1 {args.Name}");
        return null;
    }

    private static void TestCallback()
    {
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
        var remoteAssembly = AppDomain.CurrentDomain.Load("ConsoleApplication1");
        remoteAssembly.EntryPoint.Invoke(null, new object[] { new string[0] });
    }
}

Then, assembly ConsoleApplication1 has the following code:

(Note that Newtonsoft.Json is referenced (w/ NuGet) but has Copy Local set to false, which result in an intentional assembly resolve and FileNotFoundException)

class ConsoleProgram
{
    static void Main(string[] args)
    {
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
        try
        {
            Test();
        }
        catch (FileNotFoundException)
        {
        }
    }

    private static void Test()
    {
        JsonConvert.SerializeObject(true);
    }


    private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        Console.WriteLine($"Resolve2 {args.Name}");
        return null;
    }
}

What happens is that, if LoaderOptimization.MultiDomain attribute is not set on Main, both Resolve1 (from top-level program) and Resolve2 (from library) are called. However, as soon as LoaderOptimization.MultiDomain is set, only Resolve1 is called.

In my actual application, MultiDomain is critical to avoid JIT and initialize assemblies again (reduce second startup time from 5 second to almost nothing). As a result, I would like to understand the root cause of this bug and hopefully find a work around.

Edit: even when trying to harddcode my resolve during Resolve1, it seems like it can't cache assemblies (loading is slow). Maybe MultiDomain only works for assemblies in ApplicationBase? In that case, I suppose I will have to use the PrivateBinPath to optimize JIT. Would still like to know if the AssemblyResolve bug can be solved because there is still a few extra assemblies loaded from external path which I don't care if they are not JIT.

0

There are 0 best solutions below