Make MSDeploy (Visual Studio) not delete App_Data folder but delete everything else

asp.netIisDeploymentMsdeploy

asp.net Problem Overview


I'm using Visual Studio's Publish button to deploy my website, and want a different App_Data folder on the server. There's a checkbox for Leave extra files on destination (do not delete) which prevents my App_Data folder from getting deleted, but then it'll eventually accumulate a lot of vestigial files as the website changes.

Is there any way to make it exclude just App_Data when it deletes everything?

asp.net Solutions


Solution 1 - asp.net

It can be done when you invoke msdeploy manually - just add the following parameter:

-skip:Directory=\\App_Data

See Web Deploy Operation Settings. The path is a regular expression, so it is quite flexible.

If you deploy using the VS-generated ProjectName.deploy.cmd script, you can also pass this parameter in the _MsDeployAdditionalFlags environment variable (when running that script).

This is the best I've come up with for our needs (we have a similar situation as you). I haven't tried integrating it with VS's Publish button, since we deploy from command line.

EDIT:

I have learned a few things about MSDeploy since I posted this answer, so I thought I'd update it now.

First of all, the above skip rule skips any operations on the matching path (App_Data). If more granular control is needed, a more verbose syntax is available. For example, to skip only deletes (to keep any extra files on target server, but add any new ones and update existing ones):

-skip:skipaction='Delete',objectname='filePath',absolutepath='\\App_Data\\.*' -skip:skipaction='Delete',objectname='dirPath',absolutepath='\\App_Data\\.*'

This skips deletes of all files and all subfolders (with all their content) in App_Data, but doesn't prevent adds and updates.

Another useful thing is that skip rules can be defined in the project file (.csproj) so that they are automatically included in the .deploy.cmd script generated along with the package. This makes it unnecessary to pass them to the script through _MsDeployAdditionalFlags.

The above skip rule will be added if the following is included in csproj file:

<PropertyGroup>
  <OnBeforePackageUsingManifest>AddCustomSkipRules</OnBeforePackageUsingManifest>
</PropertyGroup>
<Target Name="AddCustomSkipRules">
  <ItemGroup>
    <MsDeploySkipRules Include="SkipDeleteAppData">
      <SkipAction>Delete</SkipAction>
      <ObjectName>filePath</ObjectName>
      <AbsolutePath>$(_Escaped_PackageTempDir)\\App_Data\\.*</AbsolutePath>
      <XPath>
      </XPath>
    </MsDeploySkipRules>
    <MsDeploySkipRules Include="SkipDeleteAppData">
      <SkipAction>Delete</SkipAction>
      <ObjectName>dirPath</ObjectName>
      <AbsolutePath>$(_Escaped_PackageTempDir)\\App_Data\\.*</AbsolutePath>
      <XPath>
      </XPath>
    </MsDeploySkipRules>
  </ItemGroup>
</Target>

(the names AddCustomSkipRules and SkipDeleteAppData are completely arbitrary; $(_Escaped_PackageTempDir) is supposed to be possibly needed, but in practice I've always seen it evaluate to an empty string)

See Web Deploy: Customizing a deployment package and https://stackoverflow.com/questions/7100751/how-to-set-msdeploy-settings-in-csproj-file for more info.

One caveat: this only adds those rules to the .deploy.cmd script, so it is useless if you want to use the graphical IIS Manager for package deployment, as it doesn't use that script (the same probably goes for deployment from VS, but I haven't checked).

Solution 2 - asp.net

From my experience, MsDeploySkipRules are only run when deploying from the command line.

If you are publishing from Visual Studio to Azure (or using another Web Deploy method), you can set the following when Publishing.

  • Remove additional files at destination
  • Exclude files from the App_Data folder

When "Remove additional files at destination" is checked, it will make a comparison between the files and folders you are deploying and the ones on the server.

Be warned, you may run into issues if you have User Generated content, e.g. Uploads. But this could be worked around by storing those folders in a different location, e.g. S3 / Azure Storage.

Web Publishing Profile

Solution 3 - asp.net

From Powershell, if you want to use msdeploy.exe or the myproj.deploy.cmd (Deploying Web Packages) produced when publishing with Web Deploy Package, in order to to skip deleting the App_Data folder and avoid the

All arguments must begin with "-"

error, you have to enclose the skip directive in triple quotes, e.g. :

myproj.deploy.cmd /y /u:myusername /p:mypass """-skip:Directory=\\App_Data"""

Solution 4 - asp.net

Have you looked at Package/Publish Web in the project settings, because you can tell it to exlude files in the App_Data folder.

Solution 5 - asp.net

For asp.net core web apps use MsDeploySkipRules in csproj.

<ItemGroup>
  <MsDeploySkipRules Include="CustomSkipFile">
    <ObjectName>filePath</ObjectName>
    <AbsolutePath><dir_name>\\app_data</AbsolutePath>
  </MsDeploySkipRules>
  <MsDeploySkipRules Include="CustomSkipFile">
    <ObjectName>dirPath</ObjectName>
    <AbsolutePath><dir_name>\\app_data</AbsolutePath>
  </MsDeploySkipRules>
</ItemGroup>

Replace <dir_name> with your root folder

https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/visual-studio-publish-profiles?view=aspnetcore-2.1#exclude-files

Solution 6 - asp.net

This isn't ideal since you may be copying a lot of files doing this (I'm not), but here's my solution for backing up a folder. Adapted to move the folder to the location from which it will be published, during the publish process. Put this in your pubxml file:

<Project>
...
<Target Name="PreserveSelectedFolder" AfterTargets="GatherAllFilesToPublish">
   <ItemGroup>
     <SITEDIR Include="$(publishUrl)\App_Data\**\*.*" />
   </ItemGroup>
   <Copy SourceFiles="@(SITEDIR)" 
      DestinationFolder="$(ProjectDir)\obj\$(Configuration)\Package\PackageTmp\%(RecursiveDir)"></Copy>
</Target>
</Project>

And if you just want to do any number of specific known files, do one Copy block per file:

<Target Name="PreserveSelectedFiles" AfterTargets="GatherAllFilesToPublish"  >
    <Copy SourceFiles="$(publishUrl)\MYFILENAME.EXT" 
      DestinationFolder="$(ProjectDir)\obj\$(Configuration)\Package\PackageTmp\" 
      Condition="Exists('$(publishUrl)\MYFILENAME.EXT')"></Copy>
</Target>

Solution 7 - asp.net

Put this in your pubxml file:

<ExcludeApp_Data>True</ExcludeApp_Data>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRei MiyasakaView Question on Stackoverflow
Solution 1 - asp.netJakub JanuszkiewiczView Answer on Stackoverflow
Solution 2 - asp.netuniquelauView Answer on Stackoverflow
Solution 3 - asp.netlefView Answer on Stackoverflow
Solution 4 - asp.netBob ValeView Answer on Stackoverflow
Solution 5 - asp.netGuido NeeleView Answer on Stackoverflow
Solution 6 - asp.netBrett LalondeView Answer on Stackoverflow
Solution 7 - asp.netpipllView Answer on Stackoverflow