It has been a while since I’ve blogged, and I still haven’t delivered on my promise that I would explain how to control the AppDomain into which an add-in will be loaded. I’m not going to deliver on that promise today, either; mostly because I think that before I can dig into some of the more advanced performance and partial-trust scenarios supported by the AddInManager, we need to talk about how to shut down add-ins that are already running.
Once the add-in is loaded, all that needs to be done is to call AddIn.Unload specifying an appropriate timeout value. Calling this method notifies the add-in that it needs to do any cleanup, and then tears down the add-ins domain.
This brings us to another one of the classes in the AIM: the AppDomainBinding. The AppDomainBinding is used to track which add-ins are loaded into which AppDomains. For example, in the event that you do not want to unload the AppDomain after the add-in unloads, you can set the AddIn.AppDomainBinding.AutoUnload property to false. In general, this is not a good practice, since unloading the AppDomain is the only means of unloading code in the CLR, but the functionality is there if you need it. The reason for auto-unloading the AppDomain by default is that since an assembly by itself cannot be unloaded, we must tear down the entire AppDomain to ensure that the user’s code has stopped executing.
Another interesting point about unloading is that it isn’t guaranteed to terminate. What if the user’s code contains an infinite loop in their OnShutdown handler? Avoiding this and other potential pitfalls caused by bugs in end-user’s code has become an entire discipline itself, so I won’t go into it here. Suffice to say there is an easy way that you can avoid the 80% case of an add-in failing to shut down: pass a timeout value to Unload. By doing so, the AIM executes the add-ins shutdown logic on another thread and waits for it to finish within the specified timeout. If it does not, the thread is aborted and the AppDomain unloaded without further delay. There are a myriad of other things that a poorly-written or malicious add-in can do to cause the hosting application to hang, but passing an appropriate timeout value should be a help in handing some of the more common errors from preventing the add-in from unloading.