AfterClean Target Doesn't Get Invoked When I Clean The Project - visual-studio-2012

I've added a 'BeforeClean' and an 'AfterClean' target to my .csproj file, originally designed to delete some build artifacts in locations outside the normal build path.
When I did a "clean" on the project, I could tell that the files weren't getting deleted; so I dumbed down the action to just spit a message out. Like the delete command, the message command isn't getting invoked (I'm expecting to see the message in the 'Output' window).
The only relevant advice I could find on the web was to make sure that you do your target definitions after you import the Microsoft.CSharp.targets file. I'm including the clip of my .csproj file with enough detail to show where my target defs are vis-a-vis the import.
As far as I can tell, I'm doing everything right; why would my targets not get invoked?
Thanks in advance.
[Update and FYI: I was able to get the Target to fire when changing Importance from 'normal' to 'high.']
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>
</PreBuildEvent>
</PropertyGroup>
<Target Name="BeforeClean">
<Message Text="Hello Clean World!" Importance="normal" ContinueOnError="true"/>
</Target>
<Target Name="AfterClean">
<Message Text="Goodbye Clean World!" Importance="normal" ContinueOnError="true"/>
</Target>
</Project>

It actually is getting invoked, you just can't see it. Run msbuild.exe with /verbosity:normal. Or change the IDE setting: Tools + Options, Projects and Solutions, Build and Run. Or change the Importance attribute to high.

<Target Name="AfterClean"> is ignored in dotnet core with <Project Sdk="Microsoft.NET.Sdk">, and the problem isn't the verbosity. Instead, the AfterTargets="Clean" approach works:
<Target Name="PrintGoodbye" AfterTargets="Clean">
<Message Text="Goodbye Clean World!" Importance="normal" ContinueOnError="true"/>
</Target>
run like:
$ dotnet clean
MSBuild version 17.3.2+561848881 for .NET
Build started 12/9/2022 9:05:04 AM.
1>Project "C:\code\dotNetBytes\Tests\Tests.csproj" on node 1 (Clean target(s)).
1>PrintGoodbye:
Goodbye Clean World!
1>Done Building Project "C:\code\dotNetBytes\Tests\Tests.csproj" (Clean target(s)).
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:00:00.82

Related

How to suppress warnings for missing Mac Server (Warning VSX1000)

We have a number of Xamarin iOS projects that are part of our main solution since we need to ensure that they compile as part of the gated check-in. However most of our developers are not using iOS and hence do not configure a connection to a Mac build agent.
During build locally and on our servers, we see this warning:
C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Xamarin\iOS\Xamarin.iOS.Windows.After.targets(63,5): Warning VSX1000: No Address and User has been specified in order to establish a connection to a Mac Server, so only the main assembly was compiled for project 'MyProject.iOS'. Connect to a Mac Server and try again to build the full application.
Is there some way of configuring whether this should be a warning, so that we can remove it from the Error List in Visual Studio and the build log from the server? Preferably it should be done in the projects so it could be set once for everyone.
We are using latest Visual Studio 2017 and TFS 2017 Update 2 and build vNext.
A dirty workaround is to override the targets that produce the warning - in my case that's fine as I don't need them.
In our iOS project files I conditionally (if a server address is defined) import a target file, AvoidMacBuildWarning.target, that replaces a number of targets.
Parts of the project file:
...
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets"/>
<Import Project="AvoidMacBuildWarning.target" Condition=" '$(ServerAddress)' == '' " />
<ItemGroup>
...
AvoidMacBuildWarning.target:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="_SayHello">
<Message Text="Warning (demoted to message) VSX1000: No Address and User has been specified in order to establish a connection to a Mac Server, so only the main assembly was compiled for project 'MediumService.iOS'. Connect to a Mac Server and try again to build the full application." />
</Target>
<Target Name="_SayGoodbye">
</Target>
<Target Name="_DetectSdkLocations">
</Target>
<Target Name="_CollectBundleResources">
</Target>
<Target Name="_PackLibraryResources">
</Target>
<Target Name="CopyFilesToMacOutputDirectory">
</Target>
</Project>
We do nothing special to change the warning behavior in VSTS/TFS build comparing with local build through visual studio.
As far as I known, suppressing warnings with MSB prefix is still not possible. Refer to: Supress/Disable/Solve Visual Studio Build Warning
You could give a try with /property:WarningLevel=0through MSBuild argument. Not sure if it will work with this kind of warning above. If not, afraid there is no way to bypass it.
You should use /nowarn:VSX1000 per msbuild documentation
I'd like to add a small variation of Tore Østergaard's answer in case you converted your CSPROJ to an SDK-style project (which iOS projects at this time are usually not, but you can make it work).
In an SDK-style project the "system" targets and props are imported via an SDK attribute at the top of the CSPROJ, like this:
<Project Sdk="MSBuild.Sdk.Extras">
... various project settings ...
</Project>
But if you try to use Tore Østergaard's answer, it won't work, because that answer's target overrides will be themselves overwritten by the SDK's targets (which are always imported last).
The workaround is to manually import the SDK targets and props so that you can control their order:
<Project>
<!--
The SDK is imported manually so that certain targets can be overridden (see bottom of file).
Otherwise we could use Project Sdk="MSBuild.Sdk.Extras"
-->
<Import Project="Sdk.props" Sdk="MSBuild.Sdk.Extras" />
... various project settings ...
<!-- See comment at top of file about manually importing SDK -->
<Import Project="Sdk.targets" Sdk="MSBuild.Sdk.Extras" />
<!--
These targets must be imported last so that they override the SDK-provided targets.
These override the Mac build agent command because they are not needed on CI.
-->
<Import Project="AvoidMacBuildWarning.targets" Condition=" '$(SkipMacBuild)' == 'true' " />
</Project>
Note: I also changed the condition to be a specific condition SkipMacBuild, but you can use whatever condition you want that makes sense for your build.
I also had to add an additional "empty target" to AvoidMacBuildWarning.targets to ensure they were also quieted. My full AvoidMacBuildWarning.targets looks like this:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Inspired by https://stackoverflow.com/a/47182083 from Tore Østergaard -->
<Target Name="_SayHello">
<Message Text="INFO: This would have been MSBuild warning VSX1000, but it has been ignored by importing this targets file." />
</Target>
<Target Name="_SayGoodbye">
</Target>
<Target Name="_DetectSdkLocations">
</Target>
<Target Name="_CollectBundleResources">
</Target>
<Target Name="_PackLibraryResources">
</Target>
<Target Name="CopyFilesToMacOutputDirectory">
</Target>
<Target Name="_VerifyBuildSignature">
</Target>
<Target Name="_VerifyXcodeVersion">
</Target>
</Project>

How to run build tasks with Node.js tools for Visual Studio

I'm trying to run this jar to serve my JavaScript code for my node application every time the user runs the project. I've tried editing the .njsproj file to include my custom build task (see below) but I think I've reached the opinion that the .njsproj files do not work in the same way as other visual studio project files.
Is there anyway I can automate my task?
Can't find anything helpful or that works on Google. Don't mind what technology is used to do the job as long as it can be automated.
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Plovr>plovr\plovr.jar</Plovr>
<PlovrConfig>plovr\plovr-config-debug.js</PlovrConfig>
</PropertyGroup>
<Target Name="BeforeBuild">
<Message Text="Plovr: $(Plovr)"/>
<Message Text="PlovrConfig: $(PlovrConfig)"/>
<Exec Command=""C:\Program Files (x86)\Java\jre7\bin\java.exe" -jar $(Plovr) build $(PlovrConfig)"/>
</Target>
</Project>

(Solution-Wide pre/post events) MSBuild target executes in command line but not in VS

Basically, I am trying to implement some pre and post build events for an entire solution instead of just standalone projects. I have seen this question around here before, but not addressing the same problem. I have created two .targets files by the name of after.TestSolution.sln.targets and before.TestSolution.sln.targets. Within each:
before
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CreateFile" BeforeTargets="Build">
<Message Text="Creating a file" Importance="high" />
<Exec Command="C:\users\me\Desktop\CreateFiles.bat" />
</Target>
</Project>
after
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="CopyFile" AfterTargets="Build">
<Message Text="Copying a File" Importance="high" />
<Exec Command="C:\users\me\Desktop\CopyFiles.bat" />
</Target>
</Project>
These are just simple test batches to see if the events work. I then build the solution through MSBuild from command line: this works fully. MSBuild executes the code within the "before" before the solution builds and the same for the "after" afterwards. HOWEVER, the problem is when I go to build the solution from VS, the batches are never run. So, I am not sure as to why this is. I am fairly new to MSBuild tasks.
This is a known VS feature/bug. As mentioned, VS does not build in the same way as msbuild. Msbuild on the commandline generates an msbuild file from the solution (if you set the MSBUILDEMITSOLUTION environment variable to 1, you'll see a .metaproj file generated for your solution in which the before/after targets are imported). It's my understanding VS does not do that but instead invokes msbuild programatically with no extension points for the solution.

TFS 2010 build compiling TypeScript version 0.9.1.1

I'm hoping to stop including the generated JavaScript files in TFS source control, but I haven't managed to get the compiler to run on a build.
I've followed this chap's example and edited the project file to give me:
<ItemGroup>
<TypeScriptCompile Include="$(ProjectDir)\**\*.ts" />
</ItemGroup>
<Target Name="BeforeBuild">
<Message Text="Before Build" Importance="high" />
<CallTarget Targets="TypeScriptBuild"/>
</Target>
<Target Name="TypeScriptBuild" Inputs="#(TypeScriptCompile)" Outputs="%(Identity).Dummy" Condition="'$(CompileTypeScript)'=='true'">
<Message Text="Building typescript file - #(TypeScriptCompile)" Importance="high" />
<Exec Command=""$(MSBuildProgramFiles32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\TypeScript\tsc" -target ES3 "#(TypeScriptCompile)"" />
</Target>
I've changed the file location where the tsc executable is and removed the TypeScript version information, but it isn't doing anything for me. I'm a complete newbie at this build stuff so would appreciate any help, or tips on how to debug it.
Edit 1
Removed
<ItemGroup>
<TypeScriptCompile Include="$(ProjectDir)\**\*.ts" />
</ItemGroup>
as it was redundant - this is added individually for every TypeScript file in the project.
The only warnings I'm getting are about inconclusive unit tests. I assumed that <Message Text="Before Build" Importance="high" /> would produce some kind of log message but I can't see it anywhere.
Edit 2
Got it working locally within Visual Studio by putting
<Target Name="BeforeBuild">
<Message Text="Compiling typescript...">
</Message>
<Exec Command=""$(MSBuildProgramFiles32)\Microsoft SDKs\TypeScript\tsc" -target ES3 #(TypeScriptCompile ->'"%(fullpath)"', ' ')" />
at the end of the .csproj file. For some reason this doesn't work when TFS is building it. If I change the TypeScript compiler file location to something nonsensical it complains, but when it's correct there are no JavaScript files produced.
You really shouldn't have to do any of this. Make sure this line is in your csproj, before the </project>
<Import Project="$(VSToolsPath)\TypeScript\Microsoft.TypeScript.targets" />
Then install TypeScript on the build machine. Also you need to make sure the Build Action of the .ts files is set to TypeScriptCompile. At this point, TypeScript will compile your .ts files and generate the js files. You won't (and shouldn't) check the .js files into your code repository.
Unit Tests
You really want your unit tests building with the rest of your code. Even more, you can run these unit tests at build time and use them to fail the build if any of those tests fail!
Check out this post on msdn and this post on codeplex to help get you started. It will involve using Chutzpah. Also, be aware that the way your .js bundling / delivery may be different when using Chutzpah, since Chutzpah will have to build that bundle for you and I'm not sure how your actual site is doing it.

Missing Second-Level Binary References with MSBuild Web Deployment

I am trying to do a Jenkins-based automated build/deployment of a web application (.NET 4.0). The web application project has several project references, which in turn have binary references third party DLLs.
The problem:
The second-level references (references of project references) are not pulled into the bin folder in the obj\<CONFIGURATION>\Package\PackageTmp\bin folder, used for building deployment packages.
When I build in the visual studio, the second level references are pulled into the regular build output directory.
When building with MSBuild, second level dependencies are not pulled into the regular output directory, nor into the PackageTmp\bin directory.
This is confirmed by MS as a Won't-Fix issue here.
Related questions here, here and here either do not match my problem, or offer solutions that don't work. I've reviewed all answers, not just the accepted ones.
My build command looks like this (using MSBuild 4.0):
MSBuild MySolution.sln /p:Configuration=Integration /p:platform="Any
CPU" /t:Clean,Build /p:DeployOnBuild=true /p:DeployTarget=Package
/p:AutoParameterizationWebConfigConnectionStrings=false
I've tried to manually edit Reference elements in project files, adding <Private>True</Private>, with no success.
I am trying to work around this known issue, so that my second-level dependencies are automatically and correctly pulled into the web publishing temp directory.
My current attempt combines the general approach here (customizing the web publishing pipeline by adding a MyProject.wpp.targets file next to the web project file), combined with some MSBuild code for finding DLLs here. So far this has either produced no results or broken the project file. I am new to custom MSBuild code and find it pretty arcane.
My Question: I am looking for a more complete example that works in my specific case. I think the goal is to intervene in the web publishing pipeline that gathers files for copying to the package temp directory, and adding the second-level dependencies to it.
My custom MyWebProj.wpp.targets looks like this:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<BRPathFiles Include="$(SolutionDir)..\Common\**\*.dll;$(SolutionDir)**\*.dll" />
<ConfigPathFiles Include="$(SolutionDir)..\Common\**\*.config;$(SolutionDir)**\*.config" />
</ItemGroup>
<Target Name="CopySecondLevelDependencies" BeforeTargets="CopyAllFilesToSingleFolderForPackage">
<RemoveDuplicates Inputs="#(BRPathFiles->'%(RootDir)%(Directory)')">
<Output TaskParameter="Filtered" ItemName="BRPaths" />
</RemoveDuplicates>
<RemoveDuplicates Inputs="#(ConfigPathFiles->'%(RootDir)%(Directory)')">
<Output TaskParameter="Filtered" ItemName="ConfigPaths" />
</RemoveDuplicates>
<CreateItem Include="%(BRPaths.Identity);%(ConfigPaths.Identity);">
<Output ItemName="FileList" TaskParameter="Include"/>
</CreateItem>
<CreateItem Value="#(BRSearchPath);$(ConfigSearchPath)">
<Output TaskParameter="Value" PropertyName="SecondLevelFiles" />
</CreateItem>
</Target>
<ItemGroup>
<FilesForPackagingFromProject
Include="%(SecondLevelFiles->'$(OutDir)%(FileName)%(Extension)')">
<DestinationRelativePath>$(_PackageTempDir)\bin\%(FileName)%(Extension) </DestinationRelativePath>
<FromTarget>CopySecondLevelDependencies</FromTarget>
<Category>Run</Category>
</FilesForPackagingFromProject>
</ItemGroup>
</Project>
Assuming you have collected all libraries needed at runtime in a folder outside your solution/project, have you tried just using post-build events to copy all these libraries to your main project target directory (bin) and then include that directory in your deployment package using Sayeds method: http://sedodream.com/2010/05/01/WebDeploymentToolMSDeployBuildPackageIncludingExtraFilesOrExcludingSpecificFiles.aspx (also available in this post: How do you include additional files using VS2010 web deployment packages?)?
I have (among others) the following line in my main project's post-build events:
xcopy "$(ProjectDir)..\..\Libraries\*.dll" "$(TargetDir)" /Y /S
In addition to this, I have added the following lines to my .csproj file:
<PropertyGroup>
<CopyAllFilesToSingleFolderForPackageDependsOn>
PostBuildLibraries;
$(CopyAllFilesToSingleFolderForPackageDependsOn);
</CopyAllFilesToSingleFolderForPackageDependsOn>
</PropertyGroup>
<Target Name="PostBuildLibraries">
<ItemGroup>
<_PostBuildLibraries Include="$(TargetDir)**\*" />
<FilesForPackagingFromProject Include="%(_PostBuildLibraries.Identity)">
<DestinationRelativePath>$(OutDir)%(RecursiveDir)%(Filename)%(Extension)</DestinationRelativePath>
</FilesForPackagingFromProject>
</ItemGroup>
</Target>
Be sure to add these lines after the import of the "Microsoft.WebApplication.targets". Check out the links above for more details.
This makes all the desired libraries available after each build (copied to the project's target directory) and each time I create a deployment package (copied to the obj\<CONFIGURATION>\Package\PackageTmp\bin).
Also, since I'm building my main project, not my solution, I'm using the $(ProjectDir) macro instead of the $(SolutionDir).

Resources