AppDomains


This section of the chapter deals with AppDomains. AppDomains are essentially Common Language Runtime sandboxes; that is, separated memory spaces within a runtime host. Quite a few things can be done with AppDomains. Most of the time, programmers are unaware of the fact that their code is executing within an AppDomain and as such miss out on some very powerful features of the .NET Framework.

Introduction to AppDomains

An AppDomain is both an in-memory construct used by the Common Language Runtime for isolating applications from each other, as well as a class provided by the .NET Framework. Tables 12.2 and 12.3 describe some of the more notable and useful methods and properties belonging to the AppDomain class.

Table 12.2. Methods of the AppDomain Class

Method

Description

CreateDomain

This static method creates a new AppDomain in memory within the current Common Language Runtime host process. It accepts various arguments that serve to uniquely identify the new AppDomain.

CreateInstanceFrom

This method creates an instance of a type from within the given AppDomain. When you use the new operator, you create instances within the current AppDomain. To create instances in other AppDomains, use this method.

Load

Loads an assembly into the given AppDomain.

Unload

Unloads the given AppDomain. Note that you cannot remove individual assemblies from an AppDomain; you must unload the entire domain.

GetAssemblies

This method gets a list of all the assemblies currently loaded into the AppDomain.

GeTData

You can store name/value pairs in the AppDomain itself just as you can with CallContexts. This method retrieves a named value from the AppDomain.

SetData

This method sets a named value within the AppDomain.


Table 12.3. Properties of the AppDomain Class

Property

Description

BaseDirectory

Gets the base directory from which assemblies will be searched when being loaded.

CurrentDomain

This static method gets an instance of the currently active AppDomain in which the code is running.

Evidence

Contains the evidence and identity information for the current AppDomain.

FriendlyName

Indicates the FriendlyName of the AppDomain. In most cases, this is the name of the executable or application.

SetupInformation

This property is of type AppDomainSetup and contains assembly-binding data, including information on cache downloads, base directories, search paths, and more.


Programming with AppDomains

With that information in hand, you can now take a look at an example of programming with AppDomains. This next sample will show you how to use Getdata and SetData to store and retrieve values that have the same scope as the AppDomain. In addition, you'll see how to create new AppDomains and load instances of classes into domains other than the default.

The first thing to do is to add a new method to the AssemblyTool class. It is shown highlighted in Listing 12.5. Note the addition of the new namespaces and the fact that AssemblyTool now inherits from MarshalByRefObject. Don't worry about this class; you'll see plenty of it in this book's coverage of remoting. For now, think of it as a marker that tells the Common Language Runtime to share the same object between AppDomains instead of creating a serialized copy. If the AssemblyTool class didn't have this marker, the method in Listing 12.5 would not work properly.

Listing 12.5. The Modified AssemblyTool Class
 using System; using System.Runtime.Remoting; using System.Resources; using System.IO; using System.Xml; using System.Reflection; using System.Text; namespace SAMS.CSharpUnleashed.Chapter12.AssemblyIntro {   /// <summary>   /// This is the AssemblyTool sample class   /// </summary>   public class AssemblyTool : MarshalByRefObject   {     private static XmlDocument doc = null;     public AssemblyTool()     {     }     public static string GetAssemblyInfo()     {       // gets the Assembly in which this code is executing, not       // necessarily the Assembly of the main executable (EX       Assembly thisAssembly = Assembly.GetExecutingAssembly();       AssemblyName thisName = thisAssembly.GetName();       StringBuilder sb = new StringBuilder();       sb.AppendFormat("Assembly Name: {0}\n", thisAssembly.FullName);       sb.AppendFormat("Assembly Version: {0}\n", thisName.Version.ToString());       sb.AppendFormat("Assembly Culture: {0}\n", thisName.CultureInfo.ToString());       return sb.ToString();     }     private static void LoadEmbeddedDoc()     {       Assembly thisAssembly = Assembly.GetExecutingAssembly();       Stream s = thisAssembly.GetManifestResourceStream(         "SAMS.CSharpUnleashed.Chapter12.AssemblyIntro.EmbeddedData.xml");       doc = new XmlDocument();       doc.Load( s );     }     public static string GetDataNodeValue( int nodeId )     {       if (doc == null)       LoadEmbeddedDoc();       XmlNode node = doc.SelectSingleNode(       string.Format("//DataNode[@id='{0}']", nodeId ) );       if (node != null)         return node.InnerText;       else         return "No node found";     }     public static string GetResourceString( string id )     {       ResourceManager rm =         new ResourceManager(          "SAMS.CSharpUnleashed.Chapter12.AssemblyIntro.Strings",           Assembly.GetExecutingAssembly());       return rm.GetString( id );     }     public string GetAppDomainInfo()     {       AppDomain ad = AppDomain.CurrentDomain;       StringBuilder sb = new StringBuilder();       sb.AppendFormat("------\nAppDomain: {0}\n", ad.FriendlyName);       sb.AppendFormat("\tHash Code: {0}\n", ad.GetHashCode());       if (ad.GetData("MYVALUE") != null)         sb.AppendFormat("\tStored Value: {0}\n", ad.GetData("MYVALUE"));       foreach (Assembly asm in ad.GetAssemblies())       {         sb.AppendFormat("\tLoaded Assembly: {0}\n", asm.GetName().Name);       }       return sb.ToString();     }   } } 

The key piece here is the GetAppDomainInfo method. It uses some reflection methods to obtain information about the current AppDomain, including its name, hashcode, and even the list of all assemblies currently loaded into that AppDomain. Also note the use of Getdata to retrieve a named value. We'll be using SetData to set that value in the Harness project next.

Make sure that the AssemblyIntro project compiles, add a using statement for System.Runtime.Remoting at the top of Class1.cs, and then add the following code to the end of Class1 in the Harness project:

 // experiment with an AppDomain AssemblyTool at = new AssemblyTool(); AppDomain.CurrentDomain.SetData("MYVALUE", 1024); Console.WriteLine( at.GetAppDomainInfo()); AppDomain ad = AppDomain.CreateDomain("SecondDomain",                   null, (AppDomainSetup)null); Console.WriteLine("New domain has {0} Assemblies loaded.",                   ad.GetAssemblies().Length); ad.SetData("MYVALUE", 42); ObjectHandle handle = ad.CreateInstance(   "SAMS.CSharpUnleashed.Chapter12.AssemblyIntro",   "SAMS.CSharpUnleashed.Chapter12.AssemblyIntro.AssemblyTool"); AssemblyTool at2 = (AssemblyTool)handle.Unwrap(); Console.WriteLine( at2.GetAppDomainInfo()); Console.WriteLine("New domain has {0} Assemblies loaded.",                   ad.GetAssemblies().Length); 

In the preceding code, an instance of AssemblyTool is created in the current AppDomain. Then, using the new method, the AppDomain information is displayed. Then a new AppDomain is created and the CreateInstance method is used to create a new instance of the AssemblyTool class in the new AppDomain. Finally, the instance from the second domain is used to display the AppDomain information.

If everything works properly, you should see very clearly that the two AppDomains are very distinct. They each have their own list of loaded assemblies, and therefore have their own unique lists of loaded types. Here is the output from the new section of code added to the test Harness application:

 AppDomain: Harness.exe         Hash Code: 2         Stored Value: 1024         Loaded Assembly: mscorlib         Loaded Assembly: Harness         Loaded Assembly: SAMS.CSharpUnleashed.Chapter12.AssemblyIntro         Loaded Assembly: System.Xml         Loaded Assembly: System         Loaded Assembly: SAMS.CSharpUnleashed.Chapter12.AssemblyIntro.resources         Loaded Assembly: SAMS.CSharpUnleashed.Chapter12.AssemblyIntro.resources New domain has 1 Assemblies loaded. ------ AppDomain: SecondDomain         Hash Code: 8         Stored Value: 42         Loaded Assembly: mscorlib         Loaded Assembly: SAMS.CSharpUnleashed.Chapter12.AssemblyIntro         Loaded Assembly: System.Xml New domain has 3 Assemblies loaded. 

There is quite a bit of interesting information available here. The default domain (named Harness.exe) has several assemblies loaded; in addition, you can see two .resources assemblies loaded. These are the satellite assemblies built in the previous section of this chapter.

When the new domain is created, it contains only one loaded assembly: mscorlib. After the code loads the AssemblyTool type into the new AppDomain, you can see that it loads SAMS.CSharpUnleaded.Chapter12.AssemblyIntro (the assembly in which the AssemblyTool class resides) and System.Xml. This is because for the Common Language Runtime to be able to properly handle the AssemblyTool type, it needs metadata from the System.Xml assembly.



    Visual C#. NET 2003 Unleashed
    Visual C#. NET 2003 Unleashed
    ISBN: 672326760
    EAN: N/A
    Year: 2003
    Pages: 316

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net