When I first talked about AppDomainManagers, I mentioned that there were three ways to tell the CLR that you’d like to use the managed hosting infrastructure:
- The unmanaged hosting API
- Environment variables APPDOMAIN_MANAGER_ASM and APPDOMAIN_MANAGER_TYPE
- A set of registry keys
Of these three, which one should you pick? Obviously the unmanaged hosting API is only available to you if you’re willing to have an unmanaged component of your application. Of course if you do have an unmanaged component, and you want to have communication back and forth between the two halves, using this API and setting AppDomainManagerInitializationOptions.RegisterWithHost in your InitializeNewDomain method is a great way to get that setup.
If you’re sticking with a purely managed application, that leaves you with the other two options. Given the choice between the two, you should almost always choose the environment variables over the registry keys.
The problem with the registry keys is that there’s only one set of them for every application running under your user profile. This means that if your application chooses to set these keys it creates several different types of problems. First, every managed application that starts after the keys are set will use the AppDomainManager (unless they specify their own using one of the other two methods). Since those applications have not been tested running with your AppDomainManager, and AppDomainManagers are generally used to modify the behavior of the CLR, this will likely lead to all kinds of unpredictable behavior which will be very difficult to trace back to the source.
Even if your AppDomainManager is relatively inert and does not affect the other applications in any way, the fact that there is only one set of registry keys creates another problem. If two applications decide that they’re going to setup their AppDomainManager using these keys during setup, you have an obvious problem. However, even if two applications provide a shim program to set the keys and then kick off their real code, you still have a race condition:
- Application A sets the registry key for AppDomainManager A
- Application B sets the registry key for AppDomainManager B
- Application A starts with AppDomainManager B
- Application B starts with AppDomainManager B
The world is great for Application B, however Application A probably is not going to run very well at all since the AppDomainManager it was depending upon is not running in its process.
On the other hand, environment variables are inherited from the parent process, and can be modified by each child. Since different processes can have separate environment blocks with the same environment variables having different values, you avoid all the race conditions above.
Incidentally, one question that comes up relatively often is why didn’t we enable an application to specify its AppDomainManager in the .exe.config file? The reason is security — every managed .exe can supply an .exe.config file. Since AppDomainManagers are so powerful, we didn’t want to expose the ability to specify one to untrusted code. Instead, the only ways to set one up involve running managed code, having write access to the environment, or having write access to the registry. Since these are all trusted operations, fencing off the AppDomainManager to only applications that can perform them reduces the surface area for attack on this feature.