Application Domains

There may be times when you need create additional application domains. What for? I can think of at least two reasons:

  • There is need to limit what a class can do, for example, file I/O accesses, memory usage limits, startup directory, assembly references, and so on;
  • Dynamic code generation (types and assemblies), by using System.CodeDom or System.Reflection.Emit, will stay in the memory of the current domain for ever, which may lead to memory leaks.

An application domain (an instance of the System.AppDomain class) can be unloaded from memory, while types (System.Type) and assemblies (System.Assembly) cannot. For example, if you call:

AppDomain.Unload(AppDomain.CurrentDomain);

your program will terminate silently as the current (and, by default, only) domain of the process was unloaded.

Back to our problem; our goal is to:

  1. Create a new application domain;
  2. Applying it any restrictions we want;
  3. Creating an instance of our target class in it;
  4. Invoking the target method of the target class in it;
  5. Unloading the application domain when it is no longer needed.

Your code may look like this:

[Serializable]

class ClassThatRunsOnAnotherAppDomain: MarshalByRefObject

{

    public void DoSomething()

    {

        String fn = AppDomain.CurrentDomain.FriendlyName;

        //fn contains UnloadableDomain

    }

}

 

public class Program

{

    public static void Main(String [] e)

    {

        AppDomainSetup setup = new AppDomainSetup();

        //the Assembly.CodeBase property is a URI, so we must remove the scheme part

        setup.ApplicationBase = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase).Replace("file:\\", String.Empty);

        AppDomain domain = AppDomain.CreateDomain("UnloadableDomain", null, setup);         ClassThatRunsOnAnotherAppDomain cls = domain.CreateInstance(Assembly.GetExecutingAssembly().FullName, typeof(ClassThatRunsOnAnotherAppDomain).FullName).Unwrap() as ClassThatRunsOnAnotherAppDomain;

        CrossAppDomainDelegate del = new CrossAppDomainDelegate(cls.DoSomething);

        String fn = AppDomain.CurrentDomain.FriendlyName;

        //fn contains something like 76837b64-1-128695018546718750

        domain.DoCallBack(del);

        //do something here before calling AppDomain.Unload - be carefull, if the DoSomething method has not yet terminated, it will be terminated abruptly but silently

        AppDomain.Unload(domain);

    }

}

If you want to synchronize the call to AppDomain.Unload with the termination of the DoSomething method, the best thing is to use an event; include the following code before the call to domain.DoCallBack(del):

EventWaitHandle evt = null;

try

{

    //try to open an existing named event    evt =
EventWaitHandle.OpenExisting("EventName");

}

catch (WaitHandleCannotBeOpenedException)

{

    //named event does not exist, so create one

    evt = new EventWaitHandle(false, EventResetMode.AutoReset, "EventName");

}

and just before unloading the domain:

evt.WaitOne();

In the DoSomething method, signal termination:

evt.Set();

                             

2 Comments

Comments have been disabled for this content.