MSBuild Target that always runs when clicking build in VS2013 - msbuild

I want to run a target whenever you click build for the project in VS2013. I tried several ways including changing the DefaultTargets of the project to something custom and then have the custom target call my target and then Build. However, the problem is that it only works once. If I run it again, it doesn't seem to run anything.
Is there anyway to do this?

I came up with a solution. My major problem was that VS2013 was no longer checking if the files didn't change. I needed to add this to my project file.
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
In my particular case this was a webapp project. There are probably simpler ways, but what I wound up with was this.
I change DefaultTargets in the tag to "CustomBuild"
Then, I created a target like this.
<Target Name="CustomBuild">
<CallTarget Targets="<my custom target>" />
<CallTarget Targets="Build" />
</Target>
Now, everytime I click build it will run <my custom target>

In Visual Studio, open project properties, go to Build Events section and set post-build even command, and select "Always" from the "Run the post-build event:" drop down.

Related

Visual Studio pre-build event check to see if a directory (and file) exists and delete it if it does

Every time I do a build I would like for this Pre-build event to occur:
del $(ProjectDir)\obj\Debug\Package\PackageTmp\web.config
This works fine if the directory is there. But if the directory is not there then it will cause the build to fail. I tried doing something like this to check if the directory was there:
if Exists('$(ProjectDir)\obj\Debug\Package\PackageTmp\')
del $(ProjectDir)\obj\Debug\Package\PackageTmp\web.config
But I believe my syntax is wrong because I get a exit code of 255. What would be the proper way to get this to work?
Thanks!
Apparently this works:
if EXIST "$(ProjectDir)\obj\Debug\Package\PackageTmp\web.config" (
del "$(ProjectDir)\obj\Debug\Package\PackageTmp\web.config"
)
The above piece of code was one of the first ways I tried doing this. But it kept failing. After many more attempts I ended up restarting Visual Studio 2015 and entering that code again and then it started working.
I would use a target to accomplish this. Specifically, I would suggest overriding a BeforeBuild target. There are a couple different ways to do this, but the simplest is to modify your .vcxproj file IMHO.
At the bottom of your project file (you can edit it by right-clicking on your project in Visual Studio -> Unload Project, then right-click again and choose to edit that project) you should see an <Import ... line. Add a target after that line that's something like this:
<Target Name="BeforeBuild" Condition="Exists('$(ProjectDir)\obj\Debug\Package\PackageTmp\web.config')">
<Delete Files="$(ProjectDir)\obj\Debug\Package\PackageTmp\web.config" />
</Target>
See How to: Extend the Visual Studio Build Process for more information on overriding Before and After targets.

MSBuild - Execute Custom Targets w/o modifying individual projects

I have custom MSBuild Tasks to execute after the : AfterBuild event for each project in a solution.
I don't want to modify each Project file as:
Visual Studio wipes out all the Custom Changes done to the project file once i modify the project in Visual Studio (VS 2012 Ultimate), say add or remove a file/reference.
I don't want to use "CustomAfterMicrosoftCommonTargets" as mentioned here as there is no way to pass this command line argument while building from Visual Studio :
msbuild.exe app.proj /property:CustomAfterMicrosoftCommonTargets=custom.target
I found a solution here, but I didn't quite get it.
Can anybody please elaborate on it or help me figure out a better solution?
Update 5/12/2014:
I figured out that Visual Studio doesn't wipe out the custom changes if I am running the Visual Studio in the Administrator mode.
I can now think of having a Custom import file that has got the required overrides, but still I have to do this for each project in the solution. If somebody adds a new project, they have to remember to add this customization. I don't like this, but probably I can live with for now.
I tried to use the "CustomAfterMicrosoftCommonTargets" approach, but I was not able to set this property from the Pre-build event of Visual Studio, even running as Administrator didn't help.
I was trying to set an environment variable with same name from the Pre-Build event, but I never got the new value while MSBuild executes.
Thanks!
Finally I found an option where in I don't have to edit the individual project file.
The idea is to invoke your custom common targets file in the "AfterBuild" event that Visual Studio exposes.
IF "$(BuildingInsideVisualStudio)"=="true" (
$(MSBuildBinPath)\msbuild.exe "$(ProjectDir)CustomMSBuild.targets" /p:Configuration="$(Configuration)"/property:"ProjectUnderCompilation=$(MSBuildThisFileDirectory)$(MSBuildThisFile)"
)
So I am passing the project under compilation as a property and import that project file.
If I throw an exception in the custom task, it appears as as Compilation error on the parent project.
This worked amazingly and I am able to perform any validations on the project that was passed.
The only downside I see is that I am spawning another MSBuild.exe and I don't see any impact of that in the compilation time as of now.
Please let me know your thoughts on this implementation.
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="MyTarget">
<UsingTask AssemblyFile="$(ProjectDir)\bin\TaskLibrary.dll" TaskName="CheckProjectReferences" />
<PropertyGroup>
<ProjectUnderCompilation></ProjectUnderCompilation>
</PropertyGroup>
<Target Name="MyTarget">
<Message Text="Inside MyTarget" Importance="High" />
<CheckProjectReferences/>
</Target>
<Import Project="$(ProjectUnderCompilation)" />
</Project>

How make MSBuild build custom target specified in csproj building sln?

I am facing an issue with MSBuild I can't overcome it by myself. As a result I rely on community's wisdom.
The real situation I'm having troubles with
I have a soluiton file containing several projects with dependencies to other projects in same solution. I'd like to append a custom target to one of the project's csproj file and build it from the command line. It will allow me to make all the necessary output binaries for this project for further processing during the building of the custom target. But the main thing is that I can't figure out how to do it, googling doesn't help either.
Simplification
To make thing simplier I decided to make a new C# console project, add a simple custom target to the project's file and try to make it build. Still no success! Here what I've done so far:
Created a solution app with a default console project coreapp. This gaves me at least two files:
app.sln
coreapp\coreapp.csproj
Modified coreapp.csproj with addition of my custom target inside of the Project tag
<Target Name="SampleTarget">
<Message Text="This is a SampleTarget" />
</Target>
Run on the command line the following command
%windir%\Microsoft.NET\framework\v3.5\msbuild.exe app.sln /t:coreapp:SampleTarget
or even
%windir%\Microsoft.NET\framework\v3.5\msbuild.exe app.sln /t:coreapp.csproj:SampleTarget
Results
No luck, facing the error
MSB4057: The target "coreapp.csproj:SampleTarget" does not exist in the project.
I suspect that MSBuild thinks somehting fundamentally different from what I want it to think...
BEsides that, I also tried to set on the same command line the environment variable MSBuildEmitSolution=1 to force msbuild dump a temporary solution file it creates while processing the solution. In this file, indeed, no such target. However I guess it isn't the reason because I asked msbuild to build coreapp.proj where target SampleTarget really resides.
The question is how to build SampleTarget in this simplified scenario using solution file since potencially it can contain dependencies for the project containing this SampleTarget target?
I'd be greatful for any sort of help or firection for further investigation!
Instead of inserting a custom target in your project file, you could try creating a new standalone msbuild file, which would:
build the solution file (which builds projects)
defines your extra target
Call it app-custom-Debug.msbuild , for example.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WorkingFolder>$(MSBuildProjectDirectory)</WorkingFolder>
<Configuration>Debug</Configuration>
<SolutionFile>app.sln</SolutionFile>
</PropertyGroup>
<Target Name="Build" DependsOnTargets="Compile" />
<Target Name="Compile">
<Message Text="=== COMPILING $(Configuration) configuration ===" />
<MSBuild Projects="$(SolutionFile)"
Properties="Configuration=$(Configuration)" />
</Target>
<Target Name="SampleTarget">
<Message Text="This is a SampleTarget" />
</Target>
</Project>
Then you execute:
msbuild.exe app-custom-Debug.msbuild /t:SampleTarget
One option is to tie your SampleTarget to the standard Build targets via overriding the appropriate DependsOn property. In this case you could tell BeforeBuild that it DependsOn SampleTarget or you do the same thing with AfterBuild. This will ensure that MSBuild processes your target prior to the standard target indicated.

AfterPublish target not working

World's simplest task (see below) is not being executed after I publish my web application project. Any idea why?
<Target Name="AfterPublish">
<Copy SourceFiles="C:\A.txt" DestinationFiles="C:\B.txt" />
</Target>
Note: The following applies to VS2010 and publishing web-application projects with the "Web Deploy" publish method selected in the 'Build/Publish {projectname}' dialog.
Julien Hoarau's correct in that "Publish" is NOT the name of the msbuild target invoked in the above case; the actual target name is "MSDeployPublish".
Therefore, you have to define a "Target" element whose "AfterTarget" attribute's value is set to "MSDeployPublish" - the "Name" attribute's value does not matter (as long as it's unique among target names).
Here's how to do it:
Open the project file (e.g. *.csproj) in a text/XML editor and, just before the closing </Project> tag, add a <Target Name="CustomPostPublishAction" AfterTargets="MSDeployPublish"> element; pick a name of your choice for "CustomPostPublishAction".
Add a so-called Task child element that performs the desired action; for instance, to add a command to be passed to cmd.exe, use an <Exec Command="..." /> element.
Example:
<Target Name="CustomPostPublishActions" AfterTargets="MSDeployPublish" >
<Exec Command="echo Post-PUBLISH event: Active configuration is: $(ConfigurationName)" />
</Target>
Note:
In command strings, use XML entity(?) references in place of characters that would break XML parsing, e.g. "&gt" in place of "<".
For documentation of the <Target> element in general, see http://msdn.microsoft.com/en-us/library/t50z2hka.aspx
Task-elements reference here: http://msdn.microsoft.com/en-us/library/7z253716.aspx
In general, if you need to determine the name of the msbuild.exe target that is actually invoked by Visual Studio 2010, do the following:
Go to Tools/Options..., Project and Solutions/Build and Run, select 'Detailed' (or, for even more information, 'Diagnostic') from the dropdown list labeled 'MSBuild project build output verbosity.
After running the build/publish action, e.g. Build/Publish, examine the Output window for the last occurrence of the string "Done building target" to determine the top-level target that was invoked.
Visual Studio 2013. Publish Web application to file system.
<Target Name="Moose" AfterTargets="GatherAllFilesToPublish" >
<Message Importance="high" Text="***Moooooooooooooooose***$(WPPAllFilesInSingleFolder)***$(TargetDir)" />
</Target>
Note: Make sure that build logging is set to at least to Detailed. Look for it under Tools -> Options -> Projects and Solutinos -> Build and Run -> MSBuild output verbosity. Diagnostic is also fine if you want to investigate which build target was last run before actual publish.
This seems to work in Visual Studio 2019
<Target Name="MyCustomTarget" AfterTargets="Publish">
<Copy SourceFiles="C:\A.txt" DestinationFiles="C:\B.txt" />
</Target>
You must define override the target at the end of your file, after <Import ... />
Launch MSBuild with detailed verbosity to see why your target is ignored :
msbuild project.csproj /t:Target_to_Launch /v:d
AfterPublish is called after Publish target, but Publish is not the target called when you publish a web application. Publish is the target for publishing ClickOnce application.
You'll have to find the target used when you call Publish in Visual Studio, it could be Package, WebPublish...
I'm a little lazy right now to figure out the mess of targets to find the right one for a file-based publish (which you might be interested in). What you can do in the meantime is defining an AfterBuild target in the *.pubxml file.
<Target Name="AfterBuild">
...
I recommend also turning off the property "DeleteExistingFiles" because if you copy files into the directories being published, it does a clean somewhere during the publishing process.
<DeleteExistingFiles>False</DeleteExistingFiles>

Make a target run once at the Solution level in MSBuild

I need a set of tasks that need to be executed exactly once for the entire solution. This will run tasks that will modify each project to run a separate set of tasks for each project. We had done this earlier using a separate project to the solution which had the solution level tasks, but we want to move away from that. Has anyone done this or does anyone have any suggestions on how to implement this?
Since Solution files are not in MSBuild format they are not easily extended or customized. If you want more control over the build process you would have to create a "driver" msbuild file which would replace your solution file. Inside this driver file you would build all the projects that you needed and perform some additional tasks. You would do this using the MSBuild task. Here is a sample showing how to build more than 1 project.
<Project ...>
<ItemGroup>
<Projects Include="proj01.csproj"/>
<Projects Include="proj02.csproj"/>
<Projects Include="proj03.csproj"/>
</ItemGroup>
<Target Name="BuildAll">
<MSBuild Projects="#(Projects)" BuildInParallel="true" />
</Target>
</Project>
So in your case you would just execute the tasks before you build the projects. Also note that I specified the value true for the BuildInParallel indicating that MSBuild can try and build more than one project at once.
An alternative solution is to have a single target that dispatches to an MSBuild invoked target with as many Global properties removed as possible. My team have a target in the InitialTargets of a Directory.Build.props Import'ed props file - something like:
<Target Name="Prebuild">
<MSBuild Projects="$(MSBuildThisFileFullPath)"
Targets="PrebuildWorker"
RemoveProperties="Configuration;Platform;TargetFramework;BuildProjectReferences" />
</Target>
Since MSBuild appears to synchronize parallel builds on the {project file, global properties, target} set, then by removing all of the properties you can synchronize the build and run it once for all projects being built. The downside: you have to maintain the RemoveProperties attribute - MSBuild doesn't have a way to remove all global properties. If something in the build issues a new MSBuild task with a custom property specified, then you'll get a second instance of the Target invoked.
And - of course - your build will be synchronized on this target. You could try hooking the target up by setting, say, CompileDependsOn to depend on the Prebuild target, to allow independent progress in the build. But to have the target run early and ubiquitously using InitialTargets seems like the better option.