A fantastic feature of ASP.NET is that the code for a Web site can be changed on the fly without shutting down the Web server. When a Web site’s file is changed on the hard disk, ASP.NET detects this, unloads the AppDomain that contains the old version of the files (when the last currently running request finishes), and then creates a new AppDomain, loading into it the new versions of the files. To make this happen, ASP.NET uses an AppDomain feature called
shadow copying.
Shadow Copying Assemblies
Shadow copying allows assemblies that are used in an application domain to be updated without unloading the application domain. This is particularly useful for applications that must be available continuously, such as ASP.NET sites.
The common language runtime locks an assembly file when the assembly is loaded, so the file cannot be updated until the assembly is unloaded. The only way to unload an assembly from an application domain is by unloading the application domain, so under normal circumstances, an assembly cannot be updated on disk until all the application domains that are using it have been unloaded.
When an application domain is configured to shadow copy files, assemblies from the application path are copied to another location and loaded from that location. The copy is locked, but the original assembly file is unlocked and can be updated.
The following list describes how to use the properties of the AppDomainSetup class to configure an application domain for shadow copying.
- Enable shadow copying by setting the ShadowCopyFiles property to the string value "true".
By default, this causes all assemblies in the application path to be copied to a download cache before they are loaded. This is the same cache maintained by the common language runtime to store files downloaded from other computers, and the common language runtime automatically deletes the files when they are no longer needed.
Let’s come to the point. How to enable this kind of stuff in your own application? A really simple and short example:
First, write a method to create a new app domain to host the new version of the assembly. As you might know, it’s impossible to unload an assembly once loaded in an appdomain, you can only unload the associated appdomain entirely. What the following method does is pretty straightforward: it tells the CLR (assembly loader) where to look for files and then tells it to enable shadow copying by setting the (wrong-typed; a boolean property would have been much better) ShadowCopyFiles property to the string “true”. Next, an appdomain is created with a unique name using some counter, and the assembly with the functionality is loaded (notice the _ indicates private members of the current class). This method is called when the app starts.
private void LoadAppDomain()
{
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = “c:\\temp”;
setup.ShadowCopyFiles = “true”;
AppDomain domain = AppDomain.CreateDomain(“ShadowCopy domain ” +
_domainNumber, null, setup);
_currentAssembly = domain.Load(“Server”, null);
_domainNumber++;
}
Hi,
thanks or the information concerning shadow copying.
I tries this with my Desktop application in vb.net.
However, when I was executing the LoadAppDomain() function I tried to delete the dlls for testing.
But obviously both dlls (the original and the shadow copy) could not be deleted because they were in usage.
Only with AppDomain.Unload(_domain) the shadow copy was unloaded and could be deleted.
How does this work the right way ?
setup.ApplicationBase = “c:\\temp” was not possible for me,
because ApplicationBase obviously must be the path in this case the bin-Folder where the original application is saved on disk. All other folders lead to the error message: cannot found the dll (in this case Server.dll)
ApplicationBase -> can this be a folder on disk which I can choose ? must the dll be there too or is it copied to this folder by shadowing ?
Thanks very much ,,,,,,
This is completely useless — shadow copying doesn’t help release the lock on the assembly file at all. Even using File.ReadAllBytes() and loading the raw bytes of the assembly still keeps a lock on the file, which is totally beyond stupid. Whoever designed this clearly didn’t know what they were doing…