39

I am trying to invoke simple task after publish event. When I say "publish", I mean publish in Visual Studio, right click on project and pressing "Publish...". I have included (Imported) targets file in project file which works fine because I have already tested it on Build event. I have found at http://msdn.microsoft.com/en-us/library/ms366724.aspx that there is AfterPublish event which should do what I need, but it doesn't. I am not sure if this is a same event which should trigger on Publish in Visual Studio, someone please clarify this. My question is how to trigger any kind of task from targets file on Publish in Visual Studio?

I have tried this in targets file:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Target Name="AfterPublish">
        <Message Label="Test"></Message>        
        <Warning Label="Test"></Warning>
    </Target>   
</Project>

I am using Visual Studio 2010.

EDIT:

I am actually looking for any way to execute certain action on Publish in Visual Studio. I was also thinking of adding Build Events, but I have no idea how to determine whether it is Publish in progress or not.

EDIT: @Alexey Shcherbak thank you for your fast reply. I am getting this in my MSBuild output:

12/10/2012 12:29:40 AM:        Done executing task "CallTarget".
12/10/2012 12:29:40 AM:        Done building target "PipelinePreDeployCopyAllFilesToOneFolder" in project "PublishTestApp.csproj".
12/10/2012 12:29:40 AM:Done building project "PublishTestApp.csproj".
Deleting existing files...
Publishing folder /...
Publishing folder Account...
Publishing folder bin...
Publishing folder Scripts...
Publishing folder Styles...
========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
========== Publish: 1 succeeded, 0 failed, 0 skipped ==========

So my task will executes right after PipelinePreDeployCopyAllFilesToOneFolder but before actual coping of the files and I don't consider Publish being done yet at that point. Of course, I did actually test this, so in MSBuild task I was executing simple read from text file that is suppose to be copied in the Publish folder, and it failed.

Andrija
  • 14,037
  • 18
  • 60
  • 87

5 Answers5

24

UPDATE: seems like in VS 2019 and .NET 5 you can now use Publish target.

<Target Name="Test" AfterTargets="Publish">
    <Exec Command="blablabla" />
</Target>

Here's my old answer that also works:


MS has confirmed, that when publishing to file system they don't have any target to launch after that.

"We currently do not support executing custom targets after publish from VS for the file system protocol."

Quoted from this SO question

So what we ended up doing is:

  1. use AfterTargets="CopyAllFilesToSingleFolderForPackage" (runs just before the files are copied to the publish location)
  2. which executes a bat-file
  3. the bat-file starts with a timeout 10 command (waits 10 seconds) - for the lack of a better way.

IMPORTANT: This bat file has to be executed asynchronously so the publish process continues after it's been launched, please refer to this SO answer on how to do that.

Alex from Jitbit
  • 53,710
  • 19
  • 160
  • 149
  • 3
    Upvoted as, however unattractive, this is the only way that will actually work for publishing to the file system. That said, AfterTargets="PublishOnly" actually (and incorrectly) runs somewhat later in the process than "CopyAllFilesToSingleFolderForPackage". – karfus Jul 14 '18 at 08:36
  • This is all that works for me when publishing to the file system on Visual Studio 2017. – N73k Oct 22 '18 at 22:51
  • 2
    You can see every task that is executed when you build or publish using the approach described in [this answer](https://stackoverflow.com/a/6804854/196852). That's how I found `PublishOnly` which was the very last task that executes, or at least it was in my case. – Chris Jun 21 '19 at 20:25
  • @Chris interesting! are you saying `AfterTargets="PublishOnly"` is executed after copying all the files? – Alex from Jitbit Jul 07 '21 at 16:47
  • @AlexfromJitbit Yes, that must have been the case. – Chris Jul 07 '21 at 16:57
  • @Chris according to the docs, it seems like `PublishOnly` is intended for ClickOnce deploys only :( didn't work for me with ASP.NET 5 folder publishing for some reason. However, I updated my answer with the one that did work – Alex from Jitbit Sep 06 '21 at 09:29
  • 1
    Using `Publish` for `AfterTargets` did not work for me in VS2022. But you can use `BeforeTargets="FileSystemPublish"` and `AfterTargets="FileSystemPublish"` to run code before and after Publish to a file directory! – Eric Mutta Nov 15 '21 at 01:17
  • @EricMutta Worked for me in VS 2022, but we've since migrated to .NET Core. Maybe `Publish` works for .NET Core projects only? Not sure – Alex from Jitbit Nov 16 '21 at 08:31
  • Works in VS 2022 for a web project but not for a worker project, both .NET 5 and target to folder – ArieKanarie Dec 14 '21 at 14:48
  • @AlexfromJitbit Do you know where that command is documented? Doesn't seem to be on [the MSDN docs page](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/visual-studio-publish-profiles?view=aspnetcore-7.0#publish-profiles). – Avrohom Yisroel Jul 02 '23 at 13:42
18

The Publish context menu isn't running "Publish" target (if we are speaking about publishing website, not publishing ClickOnce package).

If you are using VS2010 - context menu will run "PipelinePreDeployCopyAllFilesToOneFolder" target, and in VS2012 (keep this in mind if you are going to switch) it will run "MSDeployPublish" target.

I suppose you should read this question and answer. Jez and I provided pretty comprehensive answer on how to hook to Before\After publish target.

In short - for MSBuild version>=4.0 you could use this approach

<Target Name="Mytarget" AfterTargets="PipelinePreDeployCopyAllFilesToOneFolder" >
    <Message Label="Test"></Message>        
    <Warning Label="Test"></Warning>
</Target>

@Edit1: use CopyAllFilesToSingleFolderForPackage instead of PipelinePreDeployCopyAllFilesToOneFolder - the files should be copied after this target. If you need to fire your target only when it launched in VS context - check the link I posted and add some more conditions - to check for Visual studio launch like this Condition="'$(BuildingInsideVisualStudio)'=='true' AND '$(VisualStudioVersion)'=='10.0'" If you add more context like what kind of target do you want to launch after publishing etc. - it could add more context and help others to understand the issue

Community
  • 1
  • 1
Alexey Shcherbak
  • 3,394
  • 2
  • 27
  • 44
  • This was the `Target` that I was looking for (if there's a blog post out there that describes ALL MSBuild targets I'd appreciate it anyone shared it). My issue was I wanted transform files to switch only on publishing, not build. – Rob Scott Feb 20 '17 at 15:35
  • @RobScott AFAIK there is no such thing - the way MSBuild is designed implies that your set of targets and their versions (and overrides) is pretty unique for your machine and depends on what SDKs \ project types \versions of msbuild and VS you have installed. It dynamically composes a build script based on your environment. This is very powerful but very fragile at the same time. So it can't have any comprehensive list of targets. You can learn how to read it's verbose logs and how to read .targets files themselves so you will be able to find what you need, but there is no cheat sheet =( – Alexey Shcherbak Feb 22 '17 at 06:37
  • @AlexeyShcherbak I was meaning the `PipelinePreDeployCopyAllFilesToOneFolder` target task. I had to change mine to, however, `CopyAllFilesToSingleFolderForPackage`. You can read about my question here -- http://stackoverflow.com/questions/42284979/msbuild-config-transform-issues-desination-folder-and-reverting-file-back-to-o/42303619#42303619 – Rob Scott Feb 22 '17 at 14:19
5

I tried every other answer but they just didn't work. In my case, I'm publishing a VSTO Add-In with VS2015, so maybe there's something different going on, but here are two options that did work:

<Target Name="AfterPublish">
  <Warning Text="publish warning 1" />
</Target>
<Target Name="CustomTarget" AfterTargets="AfterPublish">
  <Warning Text="publish warning 2" />
</Target>

Part of the reason I (and assumedly others) had a hard time with this is that the Message task doesn't seem to do anything. I was expecting text in the Output view, but nothing was showing up. There were no Message items in the Error List either, but by using Warning instead, they did show up in the Error List. Unfortunately I don't know enough about MSBuild to say why Message isn't behaving as expected.

Edit: See this excellent answer about how to see exactly which targets are being executed.

Chris
  • 3,400
  • 1
  • 27
  • 41
  • 3
    I tried these in VS.NET 2017 RC4 and AfterTargets="AfterPublish" one worked. Thanks. – dstr Mar 07 '17 at 12:37
  • The `Message` task has a default priority of "normal", but VS has a default log level of "minimal". If you want a message to be visible at the default log level, use `` – Matt Tsōnto May 11 '23 at 20:49
4

I just wrote a post on how I achieved this in Visual Studio 2013 here: http://www.alexdresko.com/2015/02/28/taking-visual-studio-build-and-publish-events-to-the-next-level/

Essentially, this is the magic:

<Target Name="Mytarget" AfterTargets="MSDeployPublish" >
    <Message Text="The name of the publish profile is $(DestinationAppRoot)"/>   
    .... Here's where you do something awesome... 
</Target>

I encourage you to read the whole post for more information.

Alex Dresko
  • 5,179
  • 3
  • 37
  • 57
  • 1
    Are there any more variables like $(DestinationAppRoot) to get to the Destination URL for example? – Gareth Hopkins Jul 28 '15 at 14:08
  • I don't know, honestly. Try searching your entire hard drive for 'DestinationAppRoot' and you might stumble across something useful. I don't really remember how I came up with the solution posted here. :) – Alex Dresko Jul 28 '15 at 18:03
  • 1
    This doesn't work for me. FYI: I'm publishing to the file system. Visual Studio 2017. – N73k Oct 22 '18 at 22:36
  • When using file system publish use: AfterTargets="WebFileSystemPublish" – Vincent Apr 02 '20 at 09:52
0

My answer for another question might be of some use.

AfterPublish script doesn't run when I publish a web app

Particularly, using the path to the 'published files', you can pass in a parameter via $(WebProjectOutputDir)\$(WPPAllFilesInSingleFolder). This would be something like c:\{path to *.csproj}\obj\{build configuration}\Package\PackageTmp.

Community
  • 1
  • 1
Terry
  • 2,148
  • 2
  • 32
  • 53
  • So perhaps this should be voted as a duplicate instead then? – Martijn Pieters Feb 23 '16 at 11:03
  • I don't know if it is 'exact duplicate'...just thought my information on the other answer might be helpful in getting him some where. Will let you flag if you deem required. Thanks. – Terry Feb 23 '16 at 16:27
  • I'm no subject expert here. If the post is not a duplicate, tailor your answer to the question, even internal links can go away and then future visitors are stuck with a 'see here' link pointing nowhere. – Martijn Pieters Feb 23 '16 at 16:47