Search code examples
c#.netappdomainvs-unit-testing-framework

Cross AppDomain call is executed in caller Domain


I create an AppDomain, create an instance of an object in the new Domain and call a method that returns the name of the current AppDomain on the wrapped object. the returned value is the name of the main program domain and not the newly created one. By the way the code is being executed as a UnitTest in VS2010.

Any Idea why the test fails?

[Serializable]
    public class DomainHelper
    {
        public string GetDomainName()
        {
            return AppDomain.CurrentDomain.FriendlyName;
        }
    }


    [TestClass]
    public class DomainTests
    {
        [TestMethod]
        public void RemoteCall()
        {
            var binDir = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);

            const string appDomainName = "TEST";
            var x = AppDomain.CreateDomain(appDomainName, null, binDir,null, false);

            var remoteType = typeof(DomainHelper);
            var remote = (DomainHelper) x.CreateInstanceAndUnwrap(remoteType.Assembly.FullName, remoteType.FullName);

            Assert.AreEqual(appDomainName, remote.GetDomainName());
        }
    }

Solution

  • Because the DomainHelper is [Serializable]. Which means when it crosses domains, it is copied and recreated in the caller's domain, and afterwards .GetDomainName is executed in the caller's domain. You can either remove the [Serializable] attribute and have the DomainHelper derive from MarshalByRefObject, then the .GetDomainName would be executed in the remote domain, or keep the [Serializable] attribute and retrieve the domain name in a constructor or initializer, like so:

    [Serializable]
    public class DomainHelper
    {
        private readonly string _domainIWasConstructedIn = AppDomain.CurrentDomain.FriendlyName;
    
        public string GetDomainName()
        {
            return _domainIWasConstructedIn;
        }
    }
    

    The initializer/constructor would then execute in the remote domain, and the relevant fields it sets would be copied when the object crosses domains.