In my current project I’m using Enterprise Library 3.1’s Caching block to cache data retrieved from web services. The caching code is implemented in a regular C# class library, and I have NUnit 2.4 tests to test it. In order to configure Enterprise Library at runtime I’m using Enterprise Library’s FileConfigurationSource to point to a separate configuration file. Works great.
However, I discovered while running my unit tests that when I ran a test and then tried to close NUnit GUI or re-run a test, there was a 5-10 second delay before the IDE closed. An AppDomainUnloadException was being thrown at the end of the delay. When I commented out the code that created the Enterprise Library CacheManager object the delay disappeared, so clearly Enterprise Library was doing something to block the AppDomain from unloading.
After some digging I found the issue. FileConfigurationSource creates a worker thread that monitors the associated configuration file for changes. The factory objects, in this case CacheManagerFactory, hold a reference to the FileConfigurationSource object. There is no way to explicitly dispose or clean up the FileConfigurationSource object itself. NUnit loads the assembly to be tested into a new AppDomain, and when it shuts down or runs another test, it tries to unload the test AppDomain. What ends up happening is that NUnit asks the AppDomain to unload, but the FileConfigurationSource’s file monitoring thread does not shut down. As a result, the AppDomain cannot be unloaded and we see the delay and the AppDomainUnloadException. Needless to say, this is REALLY annoying.
One partial solution that I found is the Enterprise Library 3.0+ method FileConfigurationSource.ResetImplementation(). If you create a FileConfigurationSource object and then immediately call the static FileConfigurationSource.ResetImplementation() method with the same file path, but pass false to the ‘refreshing’ parameter, the configuration file will not be monitored for changes. This will have the effect of shutting down the monitoring thread and allowing the AppDomain to unload… but you lose auto-refresh of configuration.
I still haven’t found a real solution to this. The ‘patterns & practices’ guys need to make FileConfigurationSource implement IDisposable or something. In the meantime, I’m forcefully killing NUnit all the time or waiting out the delay, both of which are really a pain.