June 25, 2020

Fixing the error "Web Deploy cannot modify the file on the destination because it is locked by an external process."

When you publish your web application from Visual Studio, you many encounter file lock error:

Web Deploy cannot modify the file 'MyApi.dll' on the destination because it is locked by an external process.
In order to allow the publish operation to succeed, you may need to either restart your application to release the lock, 
or use the AppOffline rule handler for .Net applications on your next publish attempt.  
Learn more at: http://go.microsoft.com/fwlink/?LinkId=221672#ERROR_FILE_IN_USE.

When you publish web application in Visual Studio, it will not force the remote app to be stopped/restarted. The Web Deploy team has introduced an AppOffline rule which provides a solution for this problem.

There could be many reasons you may want to take your app offline while publishing. For example you app has files locked which need to be updated (the reason behind above error), or you need to clear an in-memory cache for changes to take effect (like ASP.Net Core app pool will keep configuration values from appsettings.json file in memory, and you have to restart the apppool to make changes take effect, if it is not configured with auto-load option).

We can define publish profiles in Visual Studio, which are simple xml files with .pubxml extension stored under Properties\PublishProfiles.

These publish profiles contain the settings for a particular profile. You can customize these files to modify the publish process. To enable this find the .pubxml file corresponding to the publish profile you want to update. Then add the following element in the PropertyGroup element.

 <EnableMSDeployAppOffline>true</EnableMSDeployAppOffline>

The resulting publish profile will look similar to this.

<?xml version="1.0" encoding="utf-8"?>
<!--
This file is used by the publish/package process of your Web project. You can customize the behavior of this process
by editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121. 
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <EnableMSDeployAppOffline>true</EnableMSDeployAppOffline>
    <WebPublishMethod>MSDeploy</WebPublishMethod>
    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
    <LastUsedPlatform>Any CPU</LastUsedPlatform>
    <SiteUrlToLaunchAfterPublish />
    <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
    <ExcludeApp_Data>False</ExcludeApp_Data>
    <TargetFramework>netcoreapp2.2</TargetFramework>
    <ProjectGuid>51c6d4da-2c14-4beb-8113-2bea0cfa3000</ProjectGuid>
    <SelfContained>false</SelfContained>
    <_IsPortable>true</_IsPortable>
    <MSDeployServiceURL>localhost</MSDeployServiceURL>
    <DeployIisAppPath>Default Web Site/MyApi</DeployIisAppPath>
    <RemoteSitePhysicalPath />
    <SkipExtraFilesOnServer>True</SkipExtraFilesOnServer>
    <MSDeployPublishMethod>InProc</MSDeployPublishMethod>
    <EnableMSDeployBackup>False</EnableMSDeployBackup>
    <UserName />
    <_SavePWD>False</_SavePWD>
  </PropertyGroup>
</Project>

Once you save these changes, when you publish using that profile your app will be taken offline during publishing, and you will not receive above error message for file lock.

Edit .csproj file

Another way to set this property is from .csproj file, which will effect every profile in a given project.

You can place the following PropertyGroup in your project file.

<PropertyGroup>
  
  <!--... other properties-->
  
  <EnableMSDeployAppOffline>true</EnableMSDeployAppOffline>
</PropertyGroup>

Visual Studio 2017 - Create a Publish Profile

In Visual Studio you can create Publish profiles to simplify the publishing process. You can add any number of profiles within a single project to publish the application for different scenarios or environments. Once the profile is created, you can use that profile to publish the application from Visual Studio or from command line.

You can create a publish profile by right click on the project and click Publish option.

Note that you need to launch the Visual Studio under Administrator mode in order to create/save a profile.

It will open a dialog and ask you to Pick a Publish target. In this example I am selecting the option IIS, FTP, etc.

Select the IIS, FTP, etc option and click Publish button on the bottom. It will open a new dialog allow you to configure profile. Fill in the required information. In this example, I am publishing MyApp on the server localhost.

Click the Next button, it will allow you to configure more settings, like Configuration, Target Framework, Remove additional files at destination etc.

After you are satisfied with the configuration settings click on the Save button. Visual Studio's publish tool creates an xml file at Properties/PublishProfiles/{PROFILE NAME}.pubxml describing the publish profile. This file contains configuration settings that will be consumed by the publishing process. You can easily edit this xml file to customize the publish process. When you click on the Save button, it will close this dialog and returns back to the project's publish screen. It will start publishing your project first time on the target server. In IIS it will create a new website with the name you provided during publish profile, and sets the Application pool to the DefaultAppPool

If everything goes fine, after successful publishing it will open the target URL in the default browser.