SlowCheetah executes after post-build events - visual-studio-2010

I use SlowCheetah to transform my app.configs. I have a multi-project solution where one of the projects executes a post-build event where the output of the bin is copied elsewhere. I've found that SlowCheetah does it's transforms after the post-build event, so the app.config I'm copying is the pre-transformed version.
Does anyone have a suggestion of how I can execute my copy after the SlowCheetah transforms? Is this going to require that I write a custom build task?

If you are using msbuild 4.0 for building your projects - you can hook to slowcheetah targets with new AfterTargets BeforeTargets attributes.
I dont know what exactly target name you want to hook after but this code could gave you base concept how to do this
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Some_Target_Name" AfterTargets="TransformAllFiles" >
<Message Text="= Script here will run after SlowCheetah TransformAllFiles ="/>
</Target>
<Project>
Edited: I installed SlowCheetah and found that AfterTargets attribute should be "TransformAllFiles".
Just set up your target dependency AfterTargets="TransformAllFiles"

Alexey's answer leads to the correct solution but here it is in full:
Right-click your project and select Unload Project
Now right-click the project and select Edit [your project name].csproj
Scroll to the bottom and uncomment the target named AfterBuild and add this attribute AfterTargets="TransformAllFiles"
Move your post build actions into this target using the Exec command:
An example:
<Target Name="AfterBuild" AfterTargets="TransformAllFiles">
<Exec Command="ECHO Hello PostBuild World!" />
</Target>

I have bumped into this problem too... decided to update to latest version of SlowCheetah (current 2.5.8), and this problem appears to have been fixed! No more problems using post-build events to deploy a project with transformed XML!
After the NuGet package upgrade process, I had a strange issue, though... transforms were no longer happening. Editing the project like Naeem Sarfraz suggested, I have found that the SlowCheetah's PropertyGroup section was placed at the end of the .csproj.
It was just a matter of moving it to the top, near the other PropertyGroup sections, and now it works like a charm!

If you need to copy/move other .config files (other than web.config) around after the build before publishing here is how it can be done with Visual Studio 2013 (I didn't test it on earlier versions). This section can be added at the end of the .csproj file right before the closing tag </Project> and it'll be fired just before MSDeploy starts the Publishing process.
<Target Name="MoveConfigFile" BeforeTargets="MSDeployPublish">
<Move
SourceFiles="$(IntermediateOutputPath)Package\PackageTmp\ThirdPartyApp.config"
DestinationFolder="$(IntermediateOutputPath)Package\PackageTmp\bin"
OverwriteReadOnlyFiles="true"
/>
</Target>
The company I work for purchased a third party product that needs to have a .config files in the bin folder along with its assembly in order to work.
At the same time we need to process the product's .config file and be able to move it to the bin folder after transformations.
The $(IntermediateOutputPath)Package\PackageTmp folder contains the whole application that will be copied over the target server.

Related

Build target in the Publish Profile is not executing even if the Publish is successful

I have a publish profile Staging.pubxml created for a console project (.NET Core 2.1), as follows:
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Configuration>Staging</Configuration>
<Platform>Any CPU</Platform>
<TargetFramework>netcoreapp2.1</TargetFramework>
<PublishDir>bin\Release\netcoreapp2.1\publish\</PublishDir>
<SelfContained>false</SelfContained>
<_IsPortable>true</_IsPortable>
</PropertyGroup>
<Target Name="CustomActionsAfterPublish" AfterTargets="AfterPublish">
<Message Text="First occurrence" Importance="high" />
</Target>
</Project>
When I publish it (via VS2019); publish completes successfully. Yet I'am not seeing the text: First occurrence in the output window.
In VS, MSBuild output verbosity is set to Diagnostic.
Am I doing this wrong?
Am I doing this wrong?
1.Hi friend, the .pubxml file is not a good place to define custom Target.
According to your target name, you want to run the target after build target. For this situation: always we define the custom target in project file. Please try right-click your project and choose edit xxx.csproj, and add the target into it. Then reload the project and publish, then you can find the First occurrence message in the build output.
And after my test, in.csproj file, the target can't be named AfterBuild, you can change it to:
<Target Name="CustomTargetName" AfterTargets="build">
<Message Text="First occurrence" Importance="high" />
</Target>
2.Also, the way you use can work in VS2019 though we don't suggest adding it in .pubxml. But it indeed works. For the reason why you can't get the message in output window, please check if the Staging.pubxml is really called during the publish process.
(Change the value of the PublishDir to another folder, and publish it again, check if the project is published to new directory, then you'll find if the xxx.pubxml is used)
Update:
According to your .pubxml file, your project is a .net core console app instead of a asp.net core web app. This makes the difference!
I test it in both VS2017 and VS2019, and find the target works well in asp.net web app but not .net core console one. I believe for those non-web app, this kind of after publish target may not be supported.
And please check these two official documents I found:
Asp.net core: Run a target before or after publishing
.net core: Deploy .net core apps with VS
I can't find any custom-target-related info in the .net core document. So I'm afraid it might be not supported by design.
Update2:
Actually your original need is to add CopyFiles target to publish process. So I assume what you really want is to copy sth to Publish Folder after Publish process or copy sth from Publish Folder to target folder.
Though the after publish target is not supported in .net core console apps. We have corresponding workarounds:
To copy sth to Publish Folder after Publish:
For this situation, you can add a after build target to copy the files to Publish folder before publish process. I think it works for this situation:
<Target Name="CustomTarget" AfterTargets="build">
<ItemGroup>
<MySourceFiles Include="xxx\pathToTheFolderWhereYourFilesAre\*.*"/>
</ItemGroup>
<Copy
SourceFiles="#(MySourceFiles)"
DestinationFolder="$(ProjectDir)bin\Release\netcoreapp2.1\publish\"
/>
</Target>
To copy sth from Publish Folder to target folder:
For .net core console app, actually the so-called publish process is to copy files from obj folder to publish folder. See this screenShot:
Go Tools=>Options=>Project and Solutions=>Build and Run to change the build output verbosity to Detailed and you can see details in build and publish process in VS.
That's why I suggest you can Go Project=>Properties=>build events=>post-build events to use a xcopy command to copy the files to your destination folder.(Or you can use a script like above, remember to change the source path and destination path). When we want to copy the files in publish folder, actually we're trying to copy the files from obj folder. So do something after build process is enough! Not need to do it after publish process.

Sequentially build configurations in Visual Studio without MSBuild or plugins?

MSDN describes how to create a batch build, but does not provide a way to automate different batches (and one click solution for the GUI)
This question describes conditionally invoking a second build but doesn't appear to suffice for more than two sequential configurations
This question addresses the same situation, but again only for two configurations
In my test case, each configuration:
defines its own MACROS (which impact source code)
is applicable to multiple projects (class libraries). The projects are interdependent and require a specific build order in the context of the current configuration
I would like visual studio to build multiple configurations sequentially with a single build command.
Can child configurations be nested under a parent configuration, and be executed sequentially by visual studio when the parent configuration is built?
UPDATE : ATTEMPTED SOLUTION 1 [2016-03-11]
In response to Stijn's suggested answer I've tried the following:
Setup DotNetFramework 4.5 WinForms solution with 3 test projects and with 6 Configurations:
CORE_DEBUG
CORE_RELEASE
EXTENDED_DEBUG
EXTENDED_RELEASE
Debug
Release
The Debug Configuration must:
NOT trigger it's own configuration build (i.e. 'Debug')
must trigger the CORE_DEBUG and EXTENDED_DEBUG Configurations in sequence
I've added the following modified target to the first project's project file:
<Target Name="AfterBuild" Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
Building with the 'Debug' Configuration now, causes an EXTENDED_RELEASE build to trigger. Having a look at the solution file, I see that Visual Studio decided to automatically link 'Debug' to 'EXTENDED_RELEASE':
{4F9706AA-26A9-483C-81C4-22E301C54C89}.Debug|Any CPU.ActiveCfg = EXTENDED_RELEASE|Any CPU
{4F9706AA-26A9-483C-81C4-22E301C54C89}.Debug|Any CPU.Build.0 = EXTENDED_RELEASE|Any CPU
Removing the above two lines from the solution file doesn't help, since Visual Studio just regenerates them. In summary this now has two undesirable outcomes:
Visual Studio executes a 'Debug' build for Project1
Visual Studio then executes an 'EXTENDED_RELEASE' for Project2 and Project3
Conclusion: While this approach can work, it also (first) performs debug and release configuration builds respectively. Visual Studio
also lists all 6 Configurations in the build menu (we only want Debug
and Release to be visible, and behind the scenes Debug must trigger
CORE_DEBUG and EXTENDED_DEBUG, and Release must trigger CORE_RELEASE
and EXTENDED_RELEASE)
UPDATE : ATTEMPTED SOLUTION 2 [2016-03-16]
Moving on to a makefile project solution: I've created a makefile project as specified by stijn's answer below, and it worked perfectly!
Conclusion : This is the preferred solution in my opinion because it gives the user the most power and ability to control exactly how the build(s) must be executed and how the configurations must be handled.
The principle of the second SO question can be adjusted to build more than one configuration/platform sequentially by just invoking MsBuild multiple times. For instance:
<Target Name="AfterBuild" Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<MSBuild Projects="$(MySolution)" Properties="Configuration=Release;Platform=x86"/>
<MSBuild Projects="$(MySolution)" Properties="Configuration=Debug;Platform=x64"/>
<MSBuild Projects="$(MySolution)" Properties="Configuration=Release;Platform=x64"/>
</Target>
This can be cleaned up by using item batching, removing the condition and instead automatically determining which config is invoked and then only building the others etc but that's a bit out of scope here.
I'm not really convinced doing this in an AfterBuild target is the best way though, because then you'd need to adjust one of your 'normal' projects to also trigger a build of everything else. An alternative is to add a MakeFile Project to your solution, set up it's dependencies so that it comes last in the build order (at least if that is what you need), and set it's command line to invoke msbuild in a way similar as described above. You can even keep all logic in the same project file: set the 'Build Command Line' to
msbuild $(MsBuildThisFile) /t:CustomBuild /p:Configuration=$(Configuration);Platform=$(Platform)
so building the project will 'recurse' and make it call itself again with the same properties as called with by VS, but executing the CustomBuild target where you can then build your other projects/solutions to taste.
EDIT re: update
You're almost there, but you have to go to Configuration Manager and make sure the configurations are setup properly to begin with. From the start:
create new solution, add 3 projects
right-click solution, select Configuration Manager
in the Active solution configuration combobox select new
enter CORE_DEBUG for name, select DEBUG under Copy settings from and make sure the Create new project configurations is checked like
repeat for other configurations
for EXTENDED_RELEASE for instance, it should now look like
you probably did most of this already, but somehow Debug got assigned to EXTENDED_RELEASE somehow so that is one thing you should fix; you could do that by editing the solution manually but instead of removing lines you'd have to edit them to be correct else VS just adds them again, as you noticed
Now open first project in a text editor and near the end of the file where AfterBuild is already inserted but commented out, add
<ItemGroup>
<Configurations Condition="'$(Configuration)'=='Debug'" Include="CORE_DEBUG;EXTENDED_DEBUG" />
<Configurations Condition="'$(Configuration)'=='Release'" Include="CORE_RELEASE;EXTENDED_RELEASE" />
<Projects Include="$(SolutionDir)WindowsFormsApplication1.csproj;$(SolutionDir)WindowsFormsApplication2.csproj;$(SolutionDir)WindowsFormsApplication3.csproj" />
</ItemGroup>
<Target Name="AfterBuild" Condition="'#(Configurations)' != ''">
<Message Text="Projects=#(Projects) Configuration=%(Configurations.Identity)" />
<MSBuild Projects="#(Projects)" Targets="Build" Properties="Configuration=%(Configurations.Identity)" />
</Target>
you might need to adjust the paths to the projects. This will build CORE_DEBUG and EXTENDED_DEBUG for Debug builds, and likewise for Release builds. AfterBuild is skipped when the Configurations ItemGroup is empty, i.e. when not building Debug or Release which is exactly the point.
EDIT re: makefile
You can specify multiple commands for the makefile commandline. Click the arrow next to the 'Build Command Line' box and select '' To be sure you have everything right, Configuration Manager has to be set up to only build the makefile project for Debug/Release like:
and the makefile project's commandline looks like
Alternatively, and I'd prefer this myself, you create an msbuild file with the same content as above:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Configurations Condition="'$(Configuration)'=='Debug'" Include="CORE_DEBUG;EXTENDED_DEBUG" />
<Configurations Condition="'$(Configuration)'=='Release'" Include="CORE_RELEASE;EXTENDED_RELEASE" />
<Projects Include="$(SolutionDir)WindowsFormsApplication1.csproj;$(SolutionDir)WindowsFormsApplication2.csproj;$(SolutionDir)WindowsFormsApplication3.csproj" />
</ItemGroup>
<Target Name="Build" Condition="'#(Configurations)' != ''">
<Message Text="Projects=#(Projects) Configuration=%(Configurations.Identity)" />
<MSBuild Projects="#(Projects)" Targets="Build" Properties="Configuration=%(Configurations.Identity)" />
</Target>
</Project>
and your makefile command then invokes that file like
msbuild /path/to/msbuildfile /t:Build /p:Configuration=Debug;SolutionDir=$(SolutionDir)

Use different pre-build events for different build configurations in Visual Studio

Is it possible to use different pre-build events for different build configurations in Visual Studio?
For example, I'd like both a release configuration for a beta & live system and have the relevant app.[type].config get copied to app.config before it is compiled.
At the moment the configuration settings are baked into the .settings file, using the settings from the default app.config file.
Or just put the Condition on your target ... eg.,
Condition="'$(Configuration)' == 'Debug'"
.. or on your task.
If you're using Visual Studio VB/C# simple post build events, you can hand-edit the project file to put such conditions on the PreBuildEvent/PostBuildEvent property tags; and repeat the tags for Release.
Dan (msbuild dev)
You can do this in a couple of ways, depending on your exact situation:
Option 1: Check the $(ConfigurationName) variable in your pre-build script, like so:
IF EXISTS $(ProjectDir)app.$(ConfigurationName).config
COPY $(ProjectDir)app.$(ConfigurationName).config $(ProjectDir)app.config
Option 2: Add a "BeforeCompile" MSBuild target to your project file:
<Target Name="BeforeBuild">
<!-- MSBuild Script here -->
</Target>
Option 3: Use configuration file transformations; this VSIX plug-in adds the web.config transform features to non-web projects. These are XSLT files that let you rewrite your config files on build (unlike web projects, where it happens on publish.)
To use different build events for different configuration in visual studio, open the cs proj file of the project. in the pre build section
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Condition="'$(Configuration)'=='Release'" Command="echo Release" />
<Exec Condition="'$(Configuration)'=='Debug'" Command="echo Debug" />
</Target>
The command in "Command" parameter will only execute if this condition is met.

How can I exclude a project from a build in MSBuild?

I need to build a solution, but exclude one project. How should I do it?
I searched a lot about this issue, but nothing could help.
An ItemGroup section rises the following exception:
Invalid element . Unknown task or datatype.
PropertyGroup also rises the exception.
Below is my code sample:
<project name="TI 8.1.6 build script">
<ItemGroup>
<Solution Include="${ROOT}\Core\TI Core.sln" Exclude="${ROOT}\Utilities\DTS Indexing Service\Tdi.Origami.IndexUpdaterServiceSetup\Tdi.Origami.IndexUpdaterServiceSetup.wixproj"/>
</ItemGroup>
...
</project>
How can I do this?
You can exclude projects at the solution level for a specific build configuration by using the Configuration Manager Dialog in Visual Studio:
Then you can simply invoke msbuild on the solution file specifying the build configuration to use:
msbuild /property:Configuration=Release MySolution.sln
The solution suggested by Enrico is the most versatile solution that would work always. An alternative solution might be to use a <MSBuild> task directly. This will work for you if you have all your project files under a particular directory, or be able to easily enumerate all projects you want to build (i.e. number of projects in your solution is not very big).
For example, this MSBuild file will build every project under your current directory except for a specific project:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<MyProjectReferences Include="**\*.*proj" />
<MyProjectReferences Exclude="Utilities\DTS Indexing Service\Tdi.Origami.IndexUpdaterServiceSetup\Tdi.Origami.IndexUpdaterServiceSetup.wixproj" />
</ItemGroup>
<Target Name="BuildAllExceptWixProject">
<MSBuild Projects="#(MyProjectReferences)" Targets="Build" />
</Target>
</Project>
Then you can build that using command line msbuild <myproject> /t:BuildAllExceptWixProject
In your solution file (.sln), remove the Build.0 entries. For example:
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MyProject", "MyProject.vcxproj", "{2281D9E7-5261-433D-BB04-176A61500CA3}"
EndProject
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2281D9E7-5261-433D-BB04-176A61500CA3}.Debug|x86.Build.0 = Debug|x64
If you delete this "Build.0" entry, it will load in the solution fine, but will not be built, either through the GUI or via external MSBuild.
Since VS 2019 and MSBuild 16.7, the right way is to use Solution filters. Ref
create a master.proj file:
in another ItemGroup add DefaultExclude properties for programs - put it in front of the solution
-- BA was Canadian
Configuration=Release
Release
drop the master.proj into the directory with the programs and msbuild the master.proj
compiles everything except... that HelloWorld

VS2010 Web Publish command line version of File System deploy

Folks,
In a nutshell, I want to replicate this dialog:
It's a Visual Studio 2010 ASP.Net MVC project. If I execute this command, I get all the files I want, including the transformed web.configs in the "C:\ToDeploy" directory.
I want to replicate this on the command line so I can use it for a QA environment build.
I've seen various articles on how to do this on the command line for Remote Deploys, but I just want to do it for File System deploys.
I know I could replicate this functionality using nAnt tasks or rake scripts, but I want to do it using this mechanism so I'm not repeating myself.
I've investigated this some more, and I've found these links, but none of them solve it cleanly:
VS 2008 version, but no Web.Config transforms
Creates package, but doesn't deploy it..do I need to use MSDeploy on this package?
Deploys package after creating it above...does the UI really do this 2 step tango?
Thanks in advance!
Ok, finally figured this out.
The command line you need is:
msbuild path/to/your/webdirectory/YourWeb.csproj /p:Configuration=Debug;DeployOnBuild=True;PackageAsSingleFile=False
You can change where the project outputs to by adding a property of outdir=c:\wherever\ in the /p: section.
This will create the output at:
path/to/your/webdirectory/obj/Debug/Package/PackageTmp/
You can then copy those files from the above directory using whatever method you'd like.
I've got this all working as a ruby rake task using Albacore. I am trying to get it all done so I can actually put it as a contribution to the project. But if anyone wants the code before that, let me know.
Another wrinkle I found was that it was putting in Tokenized Parameters into the Web.config. If you don't need that feature, make sure you add:
/p:AutoParameterizationWebConfigConnectionStrings=false
I thought I'd post a another solution that I found, I've updated this solution to include a log file.
This is similar to Publish a Web Application from the Command Line, but just cleaned up and added log file. also check out original source http://www.digitallycreated.net/Blog/59/locally-publishing-a-vs2010-asp.net-web-application-using-msbuild
Create an MSBuild_publish_site.bat (name it whatever) in the root of your web application project
set msBuildDir=%WINDIR%\Microsoft.NET\Framework\v4.0.30319
set destPath=C:\Publish\MyWebBasedApp\
:: clear existing publish folder
RD /S /Q "%destPath%"
call %msBuildDir%\msbuild.exe MyWebBasedApp.csproj "/p:Configuration=Debug;PublishDestination=%destPath%;AutoParameterizationWebConfigConnectionStrings=False" /t:PublishToFileSystem /l:FileLogger,Microsoft.Build.Engine;logfile=Manual_MSBuild_Publish_LOG.log
set msBuildDir=
set destPath=
Update your Web Application project file MyWebBasedApp.csproj by adding the following xml under the <Import Project= tag
<Target Name="PublishToFileSystem" DependsOnTargets="PipelinePreDeployCopyAllFilesToOneFolder">
<Error Condition="'$(PublishDestination)'==''" Text="The PublishDestination property must be set to the intended publishing destination." />
<MakeDir Condition="!Exists($(PublishDestination))" Directories="$(PublishDestination)" />
<ItemGroup>
<PublishFiles Include="$(_PackageTempDir)\**\*.*" />
</ItemGroup>
<Copy SourceFiles="#(PublishFiles)" DestinationFiles="#(PublishFiles->'$(PublishDestination)\%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="True" />
</Target>
this works better for me than other solutions.
Check out the following for more info:
1) http://www.digitallycreated.net/Blog/59/locally-publishing-a-vs2010-asp.net-web-application-using-msbuild
2) Publish a Web Application from the Command Line
3) Build Visual Studio project through the command line
My solution for CCNET with the Web.config transformation:
<tasks>
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe</executable>
<workingDirectory>E:\VersionesCC\Trunk_4\SBatz\Gertakariak_Orokorrak\GertakariakMS\Web</workingDirectory>
<projectFile>GertakariakMSWeb2.vbproj</projectFile>
<targets>Build</targets>
<timeout>600</timeout>
<logger>C:\Program Files\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MSBuild.dll</logger>
<buildArgs>
/noconsolelogger /p:Configuration=Release /v:diag
/p:DeployOnBuild=true
/p:AutoParameterizationWebConfigConnectionStrings=false
/p:DeployTarget=Package
/p:_PackageTempDir=E:\Aplicaciones\GertakariakMS2\Web
</buildArgs>
</msbuild>
</tasks>
On VS2012 and above, you can refer to existing publish profiles on your project with msbuild 12.0, this would be equivalent to right-click and publish... selecting a publish profile ("MyProfile" on this example):
msbuild C:\myproject\myproject.csproj "/P:DeployOnBuild=True;PublishProfile=MyProfile"
I've got a solution for Visual Studio 2012: https://stackoverflow.com/a/15387814/2164198
However, it works with no Visual Studio installed at all! (see UPDATE).
I didn't checked yet whether one can get all needed stuff from Visual Studio Express 2012 for Web installation.
A complete msbuild file with inspiration from CubanX
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="Publish">
<RemoveDir Directories="..\build\Release\Web\"
ContinueOnError="true" />
<MSBuild Projects="TheWebSite.csproj"
Targets="ResolveReferences;_CopyWebApplication"
Properties="Configuration=Release;WebProjectOutputDir=..\build\Release\Web;OutDir=..\build\Release\Web\bin\"
/>
</Target>
<Target
Name="Build"
DependsOnTargets="Publish;">
</Target>
</Project>
This places the published website in the Web..\build\Release folder

Resources