Search code examples
c#.netunit-testingmarshallingappdomain

CreateInstance from another appdomain works on console application but throws MissingMethodException when unit testing


This is the best I can do to get the Minimal, Complete, and Verifiable example (You can just copy/paste to test) :

Consider these two classes:

public class WorkerParam : MarshalByRefObject
{
    private readonly string s;

    public WorkerParam(string s)
    {
        this.s = s;
    }
}

public class Worker : MarshalByRefObject
{
    public WorkerParam T { get; }

    public Worker(WorkerParam t)
    {
        this.T = t;
    }
}

Works great when run from console application (4.5.2, AnyCPU):

class Program
{
    public static void Main()
    {
        Worker localWorker = new Worker(new WorkerParam("some string"));

        AppDomain ad = AppDomain.CreateDomain("New domain");

        Worker remoteWorker = (Worker)ad.CreateInstanceFromAndUnwrap(
            typeof(Worker).Assembly.Location,
            typeof(Worker).FullName,
            true,
            BindingFlags.Instance | BindingFlags.Public, null, new object[] { new WorkerParam("string") },
            CultureInfo.CurrentCulture, null);

        Console.ReadLine();
    }
}

The same content throws MissingMethodException when unit-testing (4.5.2, AnyCPU) :

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        Worker localWorker = new Worker(new WorkerParam("some string"));

        AppDomain ad = AppDomain.CreateDomain("New domain");

        // below line will throw MissingMethodException
        Worker remoteWorker = (Worker)ad.CreateInstanceFromAndUnwrap(
            typeof(Worker).Assembly.Location,
            typeof(Worker).FullName,
            true,
            BindingFlags.Instance | BindingFlags.Public, null, new object[] { new WorkerParam("string") },
            CultureInfo.CurrentCulture, null);
    }
}

The issue is : CreateInstanceFromAndUnwrap will throws MissingMethodException when run from unit test (Visual studio unit) but run perfectly on a console app.

Important : When I remove parameter WorkerParam from constructor, it works perfectly.


Solution

  • You need to declare the location of your assemblies since you are using more than just the Worker type:

            AppDomainSetup domaininfo = new AppDomainSetup();
            domaininfo.ApplicationBase = System.Environment.CurrentDirectory;
            AppDomain ad = AppDomain.CreateDomain("New Domain", null, domaininfo);
    
    
            Worker remoteWorker = (Worker)ad.CreateInstanceFromAndUnwrap(
                typeof(Worker).Assembly.Location,
                typeof(Worker).FullName,
                true,
                BindingFlags.Instance | BindingFlags.Public,
                null,
                new object[] { new WorkerParam("string") },
                CultureInfo.CurrentCulture, null);