TFS 2017 Build Definition: Packaging Web API Project for deployment


I have a Visual Studio solution that contains four projects:

1 Desktop app; 1 Windows Service; 2 Web API projects.

These projects have been migrated from VS2010 -> 2013 -> 2017. I've removed/edited as much legacy stuff as I recognise.

The solution builds fine in 2017.

I wish to only build one of the Web API projects, generate a deployment package, and publish the package as an artifact. A release definition is going to use WinRM to deploy the package on a Windows Server 2012 system running IIS.

In my build definition I have a MSBuild task.

The parameters of this task are as follows:

<ol><li>Project is set to the path of my webAPI .csproj in TFS source control</li> <li>Platform is set to "AnyCPU" - ("Any CPU" doesn't work.. its a known (old) issue)</li> <li>Configuration is "Release"</li> <li>MSBuild arguments are:</li> </ol>

/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation=$(Build.ArtifactStagingDirectory)\webapi.zip

<ol start="5"><li>Clean is set to true</li> </ol>

The build completes successfully, however the webapi.zip package that is produced contains a massive folder structure:



<ol><li>Why is it packing this full path? (c:\agent2_work is my build agent's directory)</li> <li>How do I change it?</li> </ol>


It's the expected behavior, it's based on your <strong>Package Location</strong>. If you publish the project in VS, you will find the similar folder structure. See <a href="https://msdn.microsoft.com/en-us/library/dd465323%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396" rel="nofollow">Create a Web Deployment Package in Visual Studio</a> for details. And <a href="https://forums.asp.net/t/2068134.aspx?My%20project%20s%20path%20in%20web%20deployment%20package" rel="nofollow">this thread</a> for your reference.

However you can change the folder structure with <strong>publish profile</strong> used in MSBuild Arguments. Following below steps to do that:

1, <strong>Create a publish profile.</strong>

To create a web deploy package in VS you will first create a publish profile for that. When you do this, a .pubxml file will be created for you under <em>Properties\PublishProfiles</em>. This is your publish profile file, its an MSBuild file. You can customize your publish process by editing this file. We will modify this file in order to update these paths in the package.

2, <strong>Edit the .pubxml file for the profile and add the following before the closing </Project> tag</strong>. (Create the target AddReplaceRuleForAppPath, and inject that into the package process by adding it to PackageDependsOn property. Once this target is executed it will add a replace rule into the MSDeployReplaceRules item group.)

<PropertyGroup> <PackagePath Condition=" '$(PackagePath)'=='' ">WebApi</PackagePath> <EnableAddReplaceToUpdatePacakgePath Condition=" '$(EnableAddReplaceToUpdatePacakgePath)'=='' ">true</EnableAddReplaceToUpdatePacakgePath> <PackageDependsOn> $(PackageDependsOn); AddReplaceRuleForAppPath; </PackageDependsOn> </PropertyGroup> <Target Name="AddReplaceRuleForAppPath" Condition=" '$(EnableAddReplaceToUpdatePacakgePath)'=='true' "> <PropertyGroup> <_PkgPathFull>$([System.IO.Path]::GetFullPath($(WPPAllFilesInSingleFolder)))</_PkgPathFull> </PropertyGroup> <!-- escape the text into a regex --> <EscapeTextForRegularExpressions Text="$(_PkgPathFull)"> <Output TaskParameter="Result" PropertyName="_PkgPathRegex" /> </EscapeTextForRegularExpressions> <!-- add the replace rule to update the path --> <ItemGroup> <MsDeployReplaceRules Include="replaceFullPath"> <Match>$(_PkgPathRegex)</Match> <Replace>$(PackagePath)</Replace> </MsDeployReplaceRules> </ItemGroup> </Target>

3, <strong>Save the Publish Profile file and check in the changes</strong>

4, <strong>Enter below MSBuild arguments:</strong> (In this example my publish profile name is 1011DP.pubxml)

/p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:PublishProfile=1011DP /p:SkipInvalidConfigurations=true /p:PackageLocation=$(Build.ArtifactStagingDirectory)

5, <strong>Run the build, then check the folder structure.</strong>

<a href="https://i.stack.imgur.com/PCWJq.png" rel="nofollow"><img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/PCWJq.png" data-original="https://i.stack.imgur.com/PCWJq.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" /></a>


To make things a bit easier I just created a nuget package that performs these steps automatically for you. See <a href="https://www.nuget.org/packages/SharpSvn.ShortMSDeployWebContentPath" rel="nofollow">https://www.nuget.org/packages/SharpSvn.ShortMSDeployWebContentPath</a>

Just installing this in your web application project from Visual Studio will change the long path below 'Contents' with just the single word 'web'


  • Go Flush() doesn't work
  • C# Vertex Edges
  • Can the ResourceLocalService be called remotely via the JSON-WS API?
  • send arraylist as parameter in volley request
  • Firebug identified xpath not working in protractor
  • Can connect between hyperledger composer and Android app?
  • Ternary Operators & Maintenance [closed]
  • how to control page breaks in tcpdf
  • Botframework Dialog migration v3 to v4
  • How to run python script in Rstudio
  • offset parameter of curand_init
  • python assign value to pandas df if falls between range of dates in another df
  • Code Map Missing in Visual Studio 15 - Preview 4
  • Laravel: Google contacts API gives empty results
  • Troubleshooting HTTPClient asynchronous POST and reading results
  • How do I click on a Cell of a DataGridView programmatically?
  • Where to store larger data for Outlook Web App?
  • Rxjs Observable Lifecycle
  • Extract and add to the data frame the values of sigma from a stan distributional linear model
  • OSGi console not shown in command line
  • Capture image from webcam and display it - OpenCV - Eclipse - Windows
  • Low Accuracy with static image on TFLite demo model
  • Quartz clustering load balancing algorithm internal implementation in Jdbcjobstore
  • JQuery and PHP validation problem?
  • Erlang needs to connect to https server?
  • Add watermark image in c#
  • ImportError with importing keras
  • Eclipse ADT Plugin crashed after updating to version 22.0
  • Http Requests not getting routed to Https NodeJs
  • Java: How to refer to subclass's static variable in abstract class?
  • Spring batch pause/resume vs stop/restart
  • How do I hide and show the contents contents of a modal?
  • no endpoints available for service \\“kubernetes-dashboard\\”
  • in Gwt, there are 2 different packages (or 2 options) for doing drag n Drop? Which one is better?
  • Windows: How do I get the mode/access rights of an already opened file?
  • Php artisan optimize is failing on production server
  • Ruby on Rails: Get mediaplayer information (iTunes, TRAKTOR, Cog; current song + playlist)
  • Why isn't stemDocument stemming?
  • Create/delete users from text file using Bash script