AppDomains and Addins

What is an Application Domain (AD)?

An Application Domain is a CLR feature that provides a unit of isolation for an application. An AD may be thought of as a lighter weight process boundary. Multiple AppDomains may be created within a host process. The CLR also verifies that the user code in an App domain is type safe. An assembly must be loaded into an application domain before it can run (see default domain). By default, the CLR loads an assembly into the Application Domain containing the code that references it.

Default Domain

When a process that hosts the CLR is created, the CLR automatically creates a default App Domain. Note that there is one CLR per process. I will come back to this in future posts when speaking to versioning, Side by Side (SxS), LockCRL version, etc.. The default App Domain remains as long as the host process lives. The Host code will undoubtly need to live as long as the process, but Add-in's (Assemblies loaded by the Host) should be isolated from the host code (see isolation).  

Isolation

An isolation boundary provides a level of protection between the Host assembly and the assemblies running in the AD(s). And of course, an Assembly in one AD is also isolated from an assembly loaded in another AD. An isolated assembly may not directly access code or resources in another assembly.

The life time of an Add-in(s) may not be as long as the life time of the host process. The Host should have control over the Add-in's life time and via isolation the Host has the opportunity to control the temporal nature of Add-in's. The host may also load multiple Add-in's into the same App Domain (clumping) where they have like semantics, such as; shared security context, life times, shared resources, etc.. In the case of ASP.net this is the model. Imagine a server application that loaded transient code into its process but never had the ability to unload and therefore release resources. The resources consumed would never be reclaimed. Can you say, kill PID or reboot periodically please ;-)

Unloadability

There is no ability within the CLR to unload an assembly (Why not?) at run time. The ability to unload an assembly is made possible via unloading an AppDomain and thus the assembly or assemblies within the AppDomain.

Boundaries

As a host, you must be conscience of the remoting boundary in your programming model. Since you are crossing an AppDomain boundary (just as you would when crossing a process boundary) your objects need to be MarshalByRef (MBRO) and instantiated via System.Runtime.Remoting. There is a brief discussion on this subject in JasonZ's blog comments. Alternatively you could use serialization but you loose the reference semantics as you are making a copy. For a great write up on value and reference types follow this link

There are versioning considerations you need to understand when communicating between components. The good news, is that we have the WinFX AddIn model libraries and forth coming guidance on design considerations to help you in this regard. I will be blogging more on this subject and maybe even co-authoring a book on the subject, if the demand is warranted (hint, hint - tell me if you would find this valuable).

Domain-neutral

Declaring assemblies to have domain-neutral behavior may be accomplished via the runtime hosting interfaces (see the framework SDK CorBindToRuntimeEx). Loading code that is domain neutral will improve performance on subsequent referencing of the same code in additional AppDomains, because the assembly code pages will be shared across the AppDomains.   

So then the question arises as to why not load everything domain-neutral. The primary reason is that domain-neutral code may not be unloaded. So does this conflict with the Add-in model guidance of unloadability and isolation? No, the majority of the scenarios addressed by the Add-in model would not have Add-in's loaded in the GAC, nor desired to be shared across AD's. Common functionality offered by the hosting application to the Add-in's, is a likely candidate for domain-neutrality as opposed to Add-in assembly neutrality. You may wish to reread that last sentence ;-). These classifications of Host provided assemblies are available to consumers (Add-in's) for the duration of the Host process. So there should be no conflict in the Add-in model isolation and unloadability recommendation and domain-neutrality.

In v1.0 and v1.1 native images that Ngen.exe produces cannot be shared (domain-neutrality) across AD's. In v2.0, native images that Ngen.exe produces can be shared (domain-neutrality) across AD's.

AppDomainSetup Properties

There are additional properties to the ones I touch on below, but I wanted to call out two primary properties of interest.

ApplicationBase

The ApplicationBase is the root directory of the application. When an AppDomain is created, it inherits the ApplicationBase of the AppDomain creator (the Host in the Add-in model). When an assembly is loaded from disk, the CLR uses this root as the probing path. It is very likely that the Add-in will be installed in a different directory than the host application. In the majority of the cases, the two are installed and uninstalled independently of each other.

ConfigurationFile

The optional configuration file, is an XML file, that has settings for the application. Most people are familiar with the concept when they think about machine.config. The configuration file can be used for declaring a startup shim, versioning rules, etc.. The configuration file will be something along the lines of MyApp.exe.config or MyApp.dll.config.

Security

A host can control policy in two ways.
1. The host can provide evidence when creating the AD.
2. The host can restrict the permissions granted at a policy level.

Simplification

It could be argued that this is a lot of work. However, the CLR and the framework, already simplify much of this for you. Of course, as the Host, you must hook up all the various functionality provided via the framework. The number of Hosts (ISV's and large application providers) that need to provide this functionality is small in comparison to the number of customizations/applications/Add-in's that will be written against a Host application. So the complexity, and thus the burden, is placed on a significantly fewer number of developers. And to further simplify the lives of ISV's, which is my current job :-), we have the System.AddIn* offering.

Creation and Assembly loading

Good news

Every good platform provides maximum flexibility. The CLR and the BCL give you all the pieces parts and runtime functionality you need!
Application Domain's: AppDomainSetup, AppDomain
Assembly loading: Assembly.Load(AssemblyName), Assembly.LoadFrom(AssemblyName), ...
Security: CodeAccessPermission, WebPermission, FileIOPermission, …
Misc: Config file support, Activation, hooking up an entry point, …

Bad news

Getting all this right is hard to do!

More Good news - Our job is to make your life easier!

While we don't save you money on your car insurance, we do wrap all this up in a nice implementation so you don't have to. This is what the System.AddIn.dll is all about. Or as we often refer to it, the "Loader". I will be bloging more on the specific's of the AddinLoader and AddinExecutor in a future post.