When you try to deploy a website using Web Deploy which is running on .NET 6, .NET 7 or later you may encounter the following error:
The first thing to do when this happens is to ensure you are using the app_offline.htm file, when deployed this file will stop the website from responding to all new requests, this however does not kill or stop any requests that may already be in process, which can cause the above ERROR_FILE_IN_USE message to be shown when deploying.
There is an officially supported way to get around the locked DLL issue, that is by using something called Shadow Copy.
Shadow Copy works by deploying the sites DLL files to a different folder which is completely separate and independent of the running website, when the deployment is finished it will then trigger an Application Pool recycle which will then change the folder used by the website to the newly deployed folder.
Shadow Copy was an experimental (but fully functional) feature in .NET 6, it is now fully stable in .NET 7.
All of this happens seamlessly behind the scenes, it behaves more like what we are used to in .NET Framework where the website would reboot during a deployment when the DLLs were touched.
You can read more about Shadow Copy, and how it works in more detail in a great blog post by Rich Strahl here.
To start using Shadow Copy with your .NET 6, .NET 7 or later applications all you need to do is follow the instructions below:
You will need to create a web.config within your Web project containing the following lines:
In the example above we have included 2 settings to enable Shadow Copy, this is due to the different key names depending on the version of .NET installed.
If the server hosting the site only has .NET 6 installed you will need the following line:
<handlerSetting name="experimentalEnableShadowCopy" value="true" />
If the server hosting the site has both .NET 6 and .NET 7 or only .NET 7+ installed then you will need the following line:
<handlerSetting name="enableShadowCopy" value="true" />
This is simply down to the feature being experimental in .NET 6 but stable in .NET 7.
(If you are unsure, you can leave both lines in the web.config)
The final setting is the location for the Shadow Copy files:
<handlerSetting name="shadowCopyDirectory" value="../ShadowCopy/" />
In the example above we are using parent paths to put the location 1 level above the Application Root, it's recommended to keep this folder outside of a publicly available location.
NOTE: the Application Pool is required to have Read and Write permissions on the folder.
That's all there is to it, 3 lines to enable Shadow Copy and remove the stresses from the dreaded locked DLL error on deployment.