Before .NET,processes were used as isolation boundaries, with every process having its private virtual memory; an application running in one process could not write to the memory of another application and thereby crash the other application. The process was used as an isolation and security boundary between applications. With the .NET architecture you have a new boundary for applications: application domains. With managed IL code, the runtime can ensure that access to the memory of another application inside a single process can’t happen. Multiple applications can run in a single process within multiple application domains.
An assembly is loaded into an application domain. In Figure 17-9 you can see process 4711 with two application domains. In application domain A, the objects one and two are instantiated, one in assembly One, and two in assembly Two. The second application domain in process 4711 has an instance one. To minimize memory consumption, the code of assemblies is only loaded once into an application domain. Instance and static members are not .shared between application domains. It’s not possible to directly access objects within another application domain; a proxy is needed instead.
the object one in application domain B cannot directly access the objects one or two in application domain A without a proxy.
The AppDomain class is used to create and terminate application domains, load and unload assemlies and types, and enumerate assemblies and threads in a domain. In this section, you program a small example to see application domains in action.
First, create a C# console application called AssemblyA. In the Main () method add a Console . wri teLine () so that you can see when this method is called. In addition, add the class Demo with a consguctor with two int values as arguments, which will be used to create instances with the AppDomain class. The AssemblyA. exe assembly will be loaded from the second application that will be created:
Running the application produces this output:
Main in domain AssemblyA.exe called.
Press any key to continue …
The second project you create is again a C# console application: DomainTest. First, display the name of the current domain using the property FriendlyName of the AppDomainclass. With the Crea teDomain () method, a new application domain with the friendly name New AppDomainis created. Then load the assembly AssemblyA into the new domain and call the Main () method by calling ExecuteAssembly ( ):
Before starting the program DomainTes t . exe, reference the assembly AssemblyA. exe with the DomainTest project. Referencing the assembly with Visual Studio 2008 copies the assembly to the project c!Vectory,so that the assembly can be found. H the assembly cannot be found, a System . IO. FileNotFoundException exception is thrown.
When DomainTest. exe is run, you get the following console output. DomainTest. exe is the friendly name of the first application domain. The second line is the output of the newly loaded assembly in the New AppDomain.With a process viewer, you will not see the process AssemblyA. exe executing because there’s no new process created. AssemblyA is loaded into the process DomainTest. exe.
Main in domain NewAppDomaincalled
Press any key to continue …
Instead of calling the Main () method in the newly loaded assembly, you can also create a new instance. In the following example, replace the ExecuteAssembly () method with a CreateInstance (). The first argument is the name of the assembly, AssemblyA. The second argument defines the type that should be instantiated: Wrox. ProCSharp .Assemblies .AppDomains. Demo.The third argument, true, means that case is ignored. System. Reflection. BindingFlags. Create Instance is a binding flag enumeration value to specify that the constructor should be called:
The results of a successful run of the application are as follows:
Now you have seen how to create and call application domains. In runtime hosts, application domains are created automatically. ASP.NET creates an application domain for each Web application that runs on a Web server. Internet Explorer creates application domains in which managed controls will run. For applications, it can be useful to create application domains if you want to unload an assembly. You can unload assemblies only by terminating an application domain.
Application domains are an extremely useful construct if assemblies are loaded dynamically, and the requirement exists to unload assemblies after use. Within the primary application domain it is not possible to get rid of loaded assemblies. , However, it is possible to end application domains where all assemblies loaded just within the application domain are cleaned from the memory.
With this knowledge about application domains it is now possible to change the WPF program created earlier. The new class CodeDriverlnAppDomain creates a new application domain using AppDomain .CreateDomain. Inside this new application domain the class CodeDri ver is instantiated using Createlns t’anceAndUnwrap ( ) . Using the CodeDri ver instance, the CompileAndRun () method is invoked before the new app-domain is unloaded again.
Tile class CodeDriver itself now is used both in the main app-domain and in the new app-domain, that’s why it is not possible to get rid of the code that this class is using. If you would like to do that you can define an interface that is implemented by the CodeDriver and just use the interface in the main app-domain. However, here this is not an issue because there’s only the need to get rid of the dynamically created assembly with the Dri ver class.
To access the class CodeDriver from a different app-domain, the class CodeDriver must derive from the base class MarshalByRefObject. Only classes that derive from this base type can be accessed across another app-domain. In the main app-domain a proxy is instantiated to invoke the methods of this class across an inter-appdomain channel.
Now you can click the Compile and Run button of the application any number of times, ami the generated assembly is always unloaded.
You can see the loaded assemblies in an app-domain with the GetAssemblies () method of the AppDomain class.