FREE BOOK

Chapter 10: Processes, AppDomains,Contexts, and Threads

Posted by Apress Free Book | C#.NET February 02, 2009
In this Chapter you drill deeper into the constitution of a .NET executable host and come to understand the relationship between Win32 processes, application domains, contexts, and threads.

Fun with AppDomains
 

To illustrate how to interact with .NET application domains programmatically, assume you have a new C# console application named AppDomainManipulator. The static PrintAllAssembliesInAppDomain() helper method makes use of AppDomain.GetAssemblies() to obtain a list of all .NET binaries hosted within the application domain in question.
 
This list is represented by an array of System.Reflection.Assembly types, and thus we are required to use the System.Reflection namespace (full details of this namespace and the Assembly type are seen in Chapter 11). Once we obtain the list of loaded assemblies, we iterate over the array and print out the friendly name and version of each module:
 
  using System.Reflection; // For the Assembly type.
 

        public static void PrintAllAssembliesInAppDomain(AppDomain ad)
         {
             Assembly[] loadedAssemblies = ad.GetAssemblies();
             Console.WriteLine("***** Here are the assemblies loaded in {0} *****\n",
             ad.FriendlyName);
             foreach (Assembly a in loadedAssemblies)
             {
                 Console.WriteLine("-> Name: {0}", a.GetName().Name);
                 Console.WriteLine("-> Version: {0}\n", a.GetName().Version);
             }
 
        }
 
Now assume you have updated the Main() method to obtain a reference to the current application domain before invoking PrintAllAssembliesInAppDomain(), using the AppDomain.CurrentDomain property. To make things a bit more interesting, notice that the Main() method launches a message box to force the assembly resolver to load the System.Windows.Forms.dll and System.dll assemblies (so be sure to set a reference to these assemblies and update your "using" statements appropriately):
 
       public static int Main(string[] args)
         {
             Console.WriteLine("***** The Amazing AppDomain app *****\n");
             // Get info for current AppDomain.
 
            AppDomain defaultAD = AppDomain.CurrentDomain;
             MessageBox.Show("This call loaded System.Windows.Forms.dll and System.dll");
             PrintAllAssembliesInAppDomain(defaultAD);
             return 0;
 
        }
 
Figure 10-6 shows the output.
 

 
 
Figure 10-6. Enumerating assemblies within a given app domain (within a given process)

Programmatically Creating New AppDomains
 

Recall that a single process is capable of hosting multiple AppDomains. While it is true that you will seldom (if ever) need to manually create AppDomains directly (unless you happen to be creating a custom host for the CLR), you are able to do so via the static CreateDomain() method. As you would guess, this method has been overloaded a number of times. At minimum you will simply specify the friendly name of the new application domain as seen here:
 
       public static int Main(string[] args)
         {
  
             // Make a new AppDomain in the current process.
 
            AppDomain anotherAD = AppDomain.CreateDomain("SecondAppDomain");
             PrintAllAssembliesInAppDomain(anotherAD);
             return 0;
 
        }
 

Now, if you run the application again (Figure 10-7), notice that the System.Windows.Forms.dll and System.dll assemblies are only loaded within the default application domain! This may seem counterintuitive if you have a background in traditional Win32 (as you might suspect that both application domains have access to the same assembly set). Recall, however, that an assembly loads into an application domain, not directly into the process itself. 
 
 
 
 Figure 10-7. A single process with two application domains

Next, notice how the SecondAppDomain application domain automatically contains its own copy of mscorlib.dll, as this key assembly is automatically loaded by the CLR for each and every application domain. This begs the question, "How can I programmatically load an assembly into an application domain?" Answer? The AppDomain.Load() method (or alternatively, AppDomain.ExecuteAssembly()). I'll hold off on this topic until I discuss the process of dynamically loading assemblies in Chapter 11 during our examination of .NET reflection services.
    
To solidify the relationship between processes, application domains, and assemblies, Figure 10-8 diagrams the internal composition of the AppDomainManipulator.exe process you have just constructed.

 
 
 Figure 10-8. The AppDomainManipulator.exe process under the hood

Programmatically Unloading AppDomains (and Hooking into Events)
 

It is important to point out that the CLR does not permit unloading individual .NET assemblies. However, using the AppDomain.Unload() method you are able to selectively unload a given application domain from its hosting process. When you do so, the application domain will unload each assembly in turn.
 
Recall that the AppDomain type defines a small set of events, one of which is DomainUnload. This is fired when a (non-default) AppDomain is unloaded from the containing process. Another event of interest is the ProcessExit event, which is fired when the default application domain is unloaded from the process (which obviously entails the termination of the process itself). Thus, if you wish to programmatically unload anotherAD from the AppDomainManipulator.exe process, and be notified when the application domain is torn down, you are able to write the following event logic:
 
    public static void anotherAD_DomainUnload(object sender, EventArgs e)
 
        { Console.WriteLine("***** Unloaded anotherAD! *****\n"); }
           // Hook into DomainUnload event.
 
            anotherAD.DomainUnload += new EventHandler(anotherAD_DomainUnload);
             // Now unload anotherAD.
 
            AppDomain.Unload(anotherAD);
 
If you wish to be notified when the default AppDomain is unloaded, modify your application to support the following event logic:
 
        private static void defaultAD_ProcessExit(object sender, EventArgs e)
 
        { Console.WriteLine("***** Unloaded defaultAD! *****\n"); }
           
     defaultAD.ProcessExit += new EventHandler(defaultAD_ProcessExit);
 
SOURCE CODE The AppDomainManipulator project is included under the Chapter 10 subdirectory.

Total Pages : 13 45678

comments