Exploring App Domains

 

1. Introduction

People working in the IT industry are often faced with the problem of isolation at all levels of IT systems architecture. For example, hardware systems are often isolated to not be destroyed in accidents together, servers are separated to minimize the effects of breaking-in, and operating system processes are separated for applications security. But in addition to those things, the .NET Framework provides its own unit of isolation – the application domain. 

2. Definition

Application domains are usually created by runtime hosts after bootstrapping the common language runtime. Application domains provide a user code isolation layer that is responsible for security, reliability and versioning. They are also responsible for loading and unloading assemblies.

Figure 1 - AppDomain bootstrapping sequence.

Application domains provide a lot of benefits:

·         A single process can wrap and isolate multiple applications.

·         A fault in one application cannot affect other applications.

·         One application can be completely unloaded without affecting the others.

·         Code executing in one application cannot access the code or resources from other applications.

·         User code permissions can be controlled by the application domain that hosts this code.

·         The application domain provides configuration settings that can determine policies, location of remote assemblies and information where to locate the assemblies that should be loaded in.

3. Communication

One of the greatest advantages of application domains is the isolation that prevents accessing the code or resources from other domains. It is possible to implement a communication between application domains, where objects can be passed between domains by proxy or by copying.

3.1. Communication by proxy

One of the methods used for communication between application domains is to use a proxy object. The proxy object must derive from MarshalByRefObject. The figure below presents a source of console application with a proxy class named MyProxy and the standard Main() method. MyProxy class consists of methods for managing messages and getting the current domain name.

namespace AppDomainProxyExample

{

    using System;

    using System.Collections.Generic;

 

    public class MyProxy : MarshalByRefObject

    {

        private List<string> messages = new List<string>();

 

        public void AddMessage(string message)

        {

            this.messages.Add(message);

        }

 

        public void PrintMessages()

        {

            foreach (var loopMessage in this.messages)

            {

                Console.WriteLine(loopMessage);

            }

        }

 

        public string GetDomainName()

        {

            return AppDomain.CurrentDomain.FriendlyName;

        }

    }

 

    public static class Program

    {

        static void Main()

        {

            var childDomain = AppDomain.CreateDomain("ChildDomain");

 

            var proxy = (MyProxy)childDomain.CreateInstanceAndUnwrap(

                typeof(MyProxy).Assembly.FullName,

                typeof(MyProxy).FullName);

 

            proxy.AddMessage(AppDomain.CurrentDomain.FriendlyName);

            proxy.AddMessage(proxy.GetDomainName());

 

            proxy.PrintMessages();

        }

    }

}

 

Figure 2 – AppDomainProxyExample

 

When AppDomainProxy.exe executable starts, the runtime is started automatically by mscoree.dll. Th­en the default AppDomain is created and the Main() method execution begins. The first line of the Main() method creates a new application domain called ChildDomain. The child domain is used to create and unwrap an instance of MyProxy class. Then two strings are added to the messages collection. The first string is name of default domain and the second string is a current domain name returned from proxy. In the figure below, the proxy object exists in the child domain so it will return the different domain name.

Figure 3 - AppDomainProxyExample.exe execution result.

 

3.2. Communication by serialization

The second method of communication between application domains is being realized by objects serialization. The figure below presents the example of a console application that shows how to pass objects between application domains. The instance of class named MyObject will be passed from one domain to the other. The MyObject class consists of the Message property and the overridden ToString() method that returns content of Message and hash code. That class was also marked with SerializableAttribute. This attribute is necessary for serialization.

namespace AppDomainSerializationExample

{

    #region Usings

    using System;

    #endregion

 

    [Serializable]

    public class MyObject

    {

        public string Message { get; set; }

 

        public override string ToString()

        {

            return this.Message + " " + this.GetHashCode().ToString();

        }

    }

 

    public static class Program

    {

        static void Main()

        {

            var childDomain = AppDomain.CreateDomain("childDomain");

 

            var myObject1 = new MyObject { Message = "Hello World!"};

            Console.WriteLine(myObject1);

 

            childDomain.SetData("MyObject", myObject1);           

            childDomain.DoCallBack(() =>

            {

                var myObject2 = (MyObject)AppDomain.CurrentDomain.GetData("MyObject");

                Console.WriteLine(myObject2);

            });

        }

    }

}

 

Figure 4 - AppDomainSerializationExample

 

The first line of Main() method works the same as it did in the previous example. Then the instance of MyObject is created and passed to the child domain by calling SetData() method. The first parameter of SetData() method is a key, and the second is an object that will be copied. Then DoCallback() method is called. That method invokes a CrossAppDomainDelegate in child domain. The delegate passed to DoCallback() is executed in the child domain. The callback picks the copy of the object passed to the domain by using the GetData() method.

 

Figure 5 - AppDomainSerializationExample.exe execution result.

 

The figure above shows the result of the Main() method execution. The messages are the same, but the hash code is not, because the object passed to the child domain was serialized.

4. Summary

Enterprise applications often provide some kind of open modules system. What about security? Imagine a situation when each of loaded modules can modify resources of host application. In optimistic case it may result in application instability, but in the worst case it may crash entire application with other modules or cause a lot of security abuses. How this problem should be solved? For example each module can be loaded into separate application domain and use only directly shared resources. Unstable module wrapped in application domain can be easily handled and unloaded.

5. References

https://msdn.microsoft.com/en-us/library/2bh4z9hs(v=vs.110).aspx