Code Listings
Chapter 21: Application Domains
Using DoCallback:
class Program { static void Main () { AppDomain newDomain = AppDomain.CreateDomain ("New Domain"); newDomain.DoCallBack (new CrossAppDomainDelegate (SayHello)); AppDomain.Unload (newDomain); } static void SayHello() { Console.WriteLine ("Hi from " + AppDomain.CurrentDomain.FriendlyName); } }
Isolating unit tests with application domains:
class Program { static void Main() { // Create 20 domains and 20 threads. AppDomain[] domains = new AppDomain [20]; Thread[] threads = new Thread [20]; for (int i = 0; i < 20; i++) { domains [i] = AppDomain.CreateDomain ("Client Login " + i); threads [i] = new Thread (LoginOtherDomain); } // Start all the threads, passing to each thread its app domain. for (int i = 0; i < 20; i++) threads [i].Start (domains [i]); // Wait for the threads to finish for (int i = 0; i < 20; i++) threads [i].Join (); // Unload the app domains for (int i = 0; i < 20; i++) AppDomain.Unload (domains [i]); Console.ReadLine (); } // Parameterized thread start – taking the domain on which to run. static void LoginOtherDomain (object domain) { ((AppDomain) domain).DoCallBack (Login); } static void Login() { Client.Login ("Joe", ""); Console.WriteLine ("Logged in as: " + Client.CurrentUser + " on " + AppDomain.CurrentDomain.FriendlyName); } } class Client { // Here's a static field that would interfere with other client logins // if running in the same app domain. public static string CurrentUser = ""; public static void Login (string name, string password) { if (CurrentUser.Length == 0) // If we're not already logged in... { // Sleep to simulate authentication... Thread.Sleep (500); CurrentUser = name; // Record that we're authenticated. } } }
Sharing data via slots:
class Program { static void Main() { AppDomain newDomain = AppDomain.CreateDomain ("New Domain"); // Write to a named slot called "Message" – any string key will do. newDomain.SetData ("Message", "guess what..."); newDomain.DoCallBack (SayMessage); AppDomain.Unload (newDomain); } static void SayMessage() { // Read from the "Message" data slot Console.WriteLine (AppDomain.CurrentDomain.GetData ("Message")); } }
Intra-process remoting:
class Program { static void Main() { AppDomain newDomain = AppDomain.CreateDomain ("New Domain"); Foo foo = (Foo) newDomain.CreateInstanceAndUnwrap ( typeof (Foo).Assembly.FullName, typeof (Foo).FullName); Console.WriteLine (foo.SayHello()); AppDomain.Unload (newDomain); Console.ReadLine(); } } public class Foo : MarshalByRefObject { public string SayHello() { return "Hello from " + AppDomain.CurrentDomain.FriendlyName; } public override object InitializeLifetimeService() { // This ensures the object lasts for as long as the client wants it return null; } }
A simple plug-in architecture:
namespace Plugin.Common { public interface ITextPlugin { string TransformText (string input); } }
namespace Plugin.Extensions { public class AllCapitals : MarshalByRefObject, Plugin.Common.ITextPlugin { public string TransformText (string input) { return input.ToUpper(); } } }
using System; using System.Reflection; using Plugin.Common; class Program { static void Main() { AppDomain domain = AppDomain.CreateDomain ("Plugin Domain"); ITextPlugin plugin = (ITextPlugin) domain.CreateInstanceFromAndUnwrap ("AllCapitals.dll", "Plugin.Extensions.AllCapitals"); // Call the TransformText method using Remoting: Console.WriteLine (plugin.TransformText ("hello")); // "HELLO" AppDomain.Unload (domain); // The AllCapitals.dll file is now completely unloaded and could // be moved or deleted. } }
Type discovery:
public class Discoverer : MarshalByRefObject { public string[] GetPluginTypeNames (string assemblyPath) { List<string> typeNames = new List<string> (); Assembly a = Assembly.LoadFrom (assemblyPath); foreach (Type t in a.GetTypes ()) if (t.IsPublic && t.IsMarshalByRef && typeof (ITextPlugin).IsAssignableFrom (t)) { typeNames.Add (t.FullName); } return typeNames.ToArray (); } }
class Program { static void Main() { AppDomain domain = AppDomain.CreateDomain ("Plugin Domain"); Discoverer d = (Discoverer) domain.CreateInstanceAndUnwrap ( typeof (Discoverer).Assembly.FullName, typeof (Discoverer).FullName); string[] plugInTypeNames = d.GetPluginTypeNames ("AllCapitals.dll"); foreach (string s in plugInTypeNames) Console.WriteLine (s); // Plugin.Extensions.AllCapitals ...
© 2007, O'Reilly Media, Inc. All rights reserved