Using Code Contracts in library code built with MSBuild - msbuild

I've started using Code Contracts in all new code I'm writing, such as in a framework library I'm building to help bootstrap IoC, O/RM, etc., in an ASP.NET MVC application. I've written a simple build script for this framework library that looks like the following:
#echo off
echo.
echo Cleaning build output (removing 'obj' and 'bin' folders)...
for /f "tokens=*" %%G in ('dir /b /ad /s bin') do rmdir /s /q "%%G"
for /f "tokens=*" %%G in ('dir /b /ad /s obj') do rmdir /s /q "%%G"
rmdir /s /q build
echo.
echo Starting the build...
call "%VS100COMNTOOLS%\vsvars32.bat"
msbuild Integration.build /target:Build
echo.
echo Done!
pause
This doesn't work. What I end up with in my build folder if I run this is, for whatever reason, assemblies that aren't fully rewritten by ccrewrite alongside .pdb.original, .rewritten and .csproj.FileListAbsolute.txt files that litter the output directory.
What does work is first building the solution in Visual Studio 2010, commenting out line 3 through 7 in the batch file and running it again. I then end up with properly rewritten assemblies and no .pdb.original nor .rewritten files.
What I've deduced from this is that Visual Studio 2010 somehow triggers the Code Contract rewriter properly so the resulting assemblies from the Visual Studio 2010 build is re-used by the command-line MSBuild call, so what my batch script basically does is just copying files to the build directory. Rather useless, in other words.
I've read this, but Jon's problem seems different from mine since ccrewrite is obviously doing something, but it's just not completing the rewriting for whatever reason. The Integration.build file builds the correct configuration (that has Code Contracts enabled in the .csproj files) and everything else looks right, it just doesn't work properly.
So, I'm wondering: How do I run MSBuild the way Visual Studio 2010 is where ccrewrite does what it's supposed to and doesn't litter my output directory with .rewritten and .pdb.original files? Does anyone have a perfect example of how an MSBuild file doing proper Code Contracts rewriting looks like?

The answer is in the script. All Visual Studio is ever going to do is run MSBuild tasks that will invoke others. One thing you can do is go to Tools|Options|Build... and turn on logging so you can see in detail which bit is doing what to generate the artifacts.
How would one do such a complex and involved thing? Read a guide to MSBuild such as Hashimi p1 and Part 2.
Then dig into the source for the build in e.g.:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Microsoft.Common.targets
The best way to get there is to open your .csproj and look what it includes and go via that (the .CSharp.targets is the first one - the one I cited comes further down the stack).
(That and wait for someone to pop in with an actual answer!)

I've played a little with Code Contract's static analysis and it is pretty cool.
Now trying to set up TeamCity build ...
Here is msbuild integration info from Microsoft Research (see page 44)

Related

Calling MS Build in post-build event giving error after build. (Code 5)

Our web apps have a post build event that copies web.config files over depending on the configuration that's being built. I wasn't around when this was created, and no one from back then exists on the team today, but it looks like our CI/Deploy server requires it, so removing it isn't an option.
Error The command "
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\msbuild" "E:\{path}\UI.IX.csproj" /t:Transform /p:Configuration=Debug.Dev;Platform=AnyCPU
Xcopy E:\{path}\obj\Debug.Dev\Web.Config E:\{path}\. /F /R /Y
("E:\{Path}\IX.PostBuild\bin\Debug.Dev\IX.PostBuild.exe" 'E:\{Path}' 'E:\{path}\' Debug.Dev /S /Y /I /D /V /C)"
exited with code 5. Please verify that you have sufficient rights to run this command.
The post-build has 3 steps:
run MS Build to update the web.config with the correct config based on configuration management
Copy the web.config into the bin/obj directory
Run a PostBuild .exe file to copy files from one project to another
We're only seeing this error come up on a handful of computers from a new office, and it's not able to be reproduced.
Visual Studio is being ran as admin, by an admin
all commands in the Post-Build event can be ran through a Command Prompt without any error
removed all but msbuild.exe command from post build - still errors (this is the culprit)
Any thoughts on how to fix this error? I don't have this error on 5 machines, but out of 3 new ones in a new office, 2 have this error.
Update
On further inspection we found out that VS was installed by the local Admin prior to joining the domain. I am not sure if this would cause any issues with permissions, but we are re-installing VS on the domain account that will be running the system to see if that fixes anything.
The cause of this issue was Antivirus software. When it was building antivirus software was scanning the new files that were created, and during this scan, Visual Studio was unable to rewrite the files.
We added the source code folder to a list of excluded folders in the AV software and it builds properly now.

XBuild reporting too many project files but works with MSBuild

I'm running the following msbuild command
msbuild /verbosity:normal /property:configuration="Release"
/property:VisualStudioVersion="12.0" /m /property:RunOctoPack="true"
/property:OctoPackEnforceAddingFiles="true" /target:"Clean" ../MYSLN.sln
which builds successfully.
I just tried running the same command using xbuild on OSX so:
xbuild /verbosity:normal /property:configuration="Release"
/property:VisualStudioVersion="12.0" /m /property:RunOctoPack="true"
/property:OctoPackEnforceAddingFiles="true" /target:"Clean" ../MYSLN.sln
which reports
MSBUILD: error MSBUILD0004: Too many project files specified
I have XBuild Engine Version 12.0 and Mono, Version 4.0.2.0
Is there some subtle mistake in how I'm listing the parameters
----EDIT----
That's being thrown here: https://github.com/mono/mono/blob/master/mcs/tools/xbuild/Parameters.cs#L140 which suggests that xbuild isn't picking up the solution file (I think)
NB, I've tried with the solution file as the first and last parameter to no avail
----EDIT----
I've added that the solution file has an uppercase name in case that is important.
----EDIT----
Ah, I've been writing a test around their parameter parsing code and it isn't recognising /m
So, I grabbed their source and wrote a test to see what was happening. And xamarin doesn't recognise the /m parameter. That's a real parameter for xbuild so I've logged https://bugzilla.xamarin.com/show_bug.cgi?id=33388 to see if they purposefully don't support it
TLDR; currently xbuild doesn't support /m as a parameter

Stop MSBuild processing immediately on compilation errors

I have written a batch file, which when executed builds a visual studio solution. The solution comprises of few C# projects. I am using MSBuild utility for this. How can i stop the build from proceeding further when there are compilation errors in any of the projects?
Further how can i get the error messages and display them on command prompt?
There's no support for stop on first failure when building a visual studio solution.
You can workaround this by taking the following steps:
Set the environment variable msbuildemitsolution to 1 (set msbuildemitsolution=1);
Invoke MSBuild in order to generate a *.proj file from the target VS solution;
In the generated *.sln.proj file change RunEachTargetSeparately="true" in the target named Build to RunEachTargetSeparately="false";
Invoke MSBuild to build the updated *.sln.proj file.
This answer is based on Dan Moseley answer to a post on MSDN Forums.
It would be easier to give you an answer if you would have posted relevant parts of your batch file. Nevertheless, for your second part of the question, here is an example how I solved almost the same issue in one of our build scripts:
msbuild.exe /m /p:Configuration=Release /v:n theSolutionFile.sln >Build.log
if ERRORLEVEL 1 goto :showerror
find "0 Warn" Build.log >nul:
if ERRORLEVEL 1 goto :showerror
goto :EOF
:showerror
echo Build error occurred
exit %ERRORLEVEL%

SolutionDir set to *Undefined* in post-build xcopy event

I have a project that has a post-build event that xcopies a DLLs to a certain directory:
xcopy "$(TargetDir)$(TargetName).dll" "$(SolutionDir)..\UdpLocationService\bin\Plugins\" /d /y
xcopy "$(TargetDir)$(TargetName).pdb" "$(SolutionDir)..\UdpLocationService\bin\Plugins\" /d /y
However, I have CruiseControl.NET set up as a build server and MSBuild is failing on building that project due to this xcopy post-build event:
MSB3073: The command "xcopy "C:\Build\Services\Windows\VehicleServer\Plugins\Payload\bin\Debug\Payload.dll" "*Undefined*..\UdpLocationService\bin\Plugins\" /d /y xcopy "C:\Build\Services\Windows\VehicleServer\Plugins\Payload\bin\Debug\Payload.pdb" "*Undefined*..\UdpLocationService\bin\Plugins\" /d /y" exited with code 4. in Microsoft.Common.targets(3397, 13)
Any suggestions to get this fixed?
I just ran into the same problem with TeamCity.
The issue here is the $(SolutionDir) property in your build file. You haven't defined it in your call to MsBuild (this is why you see the word undefined in your output).
Call msbuild with the property set, like this:
msbuild myproject.csproj /property:SolutionDir="solution directory"\
Where "solution directory" is the directory containing your solution file. Note the trailing slash, you'll need that to make sure the path is correctly formed.
I fixed this for problems with the Microsoft.SqlServer.Compact nuget package (which adds a similar post-build script), by adding:
<SolutionDir Condition="'$(SolutionDir)'=='' or '$(SolutionDir)'=='*Undefined*'">..\</SolutionDir>
right above the <PostBuildEvent>. You'll want to adjust the relative path to match your project layout.
Follow these steps:
Unload your project file (e.g. *.csproj)
Open your project file for editing
Find the AfterBuild target
Separate out the two invocations of XCopy into two distinct Exec tasks
Save your changes and Reload your project file

How can you publish a ClickOnce application through CruiseControl.NET?

I have CruiseControl.NET Version 1.4 set up on my development server. Whenever a developer checks in code, it makes a compile.
Now we're at a place where we can start giving our application to the testers. We'd like to use ClickOnce to distribute the application, with the idea being that when a tester goes to test the application, they have the latest build.
I can't find a way to make that happen with CruiseControl.NET. We're using MSBUILD to perform the builds.
We've done this and can give you some pointers to start.
2 things you should be aware of:
MSBuild can generate the necessary deployment files for you.
MSBuild won't deploy the files to the FTP or UNC share. You'll need a separate step for this.
To use MSBuild to generate the ClickOnce manifests, here's the command you'll need to issue:
msbuild /target:publish /p:Configuration=Release /p:Platform=AnyCPU; "c:\yourProject.csproj"
That will tell MSBuild to build your project and generate ClickOnce deployment files inside the bin\Release\YourProject.publish directory.
All that's left is to copy those files to the FTP/UNC share/wherever, and you're all set.
You can tell CruiseControl.NET to build using those MSBuild parameters.
You'll then need a CruiseControl.NET build task to take the generated deployment files and copy them to the FTP or UNC share. We use a custom little C# console program for this, but you could just as easily use a Powershell script.
Thanks for all the help. The final solution we implemented took a bit from every answer.
We found it easier to handle working with multiple environments using simple batch files. I'm not suggesting this is the best way to do this, but for our given scenario and requirements, this worked well. Supplement "Project" with your project name and "Environment" with your environment name (dev, test, stage, production, whatever).
Here is the tasks area of our "ccnet.config" file.
<!-- override settings -->
<exec>
<executable>F:\Source\Project\Environment\CruiseControl\CopySettings.bat</executable>
</exec>
<!-- compile -->
<msbuild>
<executable>C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe</executable>
<workingDirectory>F:\Source\Project\Environment\</workingDirectory>
<projectFile>Project.sln</projectFile>
<buildArgs>/noconsolelogger /p:Configuration=Debug /v:diag</buildArgs>
<targets>Rebuild</targets>
<timeout>0</timeout>
<logger>ThoughtWorks.CruiseControl.MsBuild.XmlLogger,ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
<!-- clickonce publish -->
<exec>
<executable>F:\Source\Project\Environment\CruiseControl\Publish.bat</executable>
</exec>
The first thing you will notice is that CopySettings.bat runs. This copies specific settings for the environment, such as database connections.
Next, the standard MSBUILD task runs. Any compile errors are caught here and handled as normal.
The last thing to execute is Publish.bat. This actually performs a MSBUILD "rebuild" again from command line, and parameters from CruiseControl are automatically passed in and built. Next, MSBUILD is called for the "publish" target. The exact same parameters are given to the publish as the rebuild was issued. This keeps the build numbers in sync. Also, our executables are named differently (i.e. - ProjectDev and ProjectTest). We end up with different version numbers and names, and this allows ClickOnce to do its thing.
The last part of Publish.bat copies the actual files to their new homes. We don't use the publish.htm as all our users are on the network, we just give them a shortcut to the manifest file on their desktop and they can click and always be running the correct executable with a version number that ties out in CruiseControl.
Here is CopySettings.bat
XCOPY "F:\Source\Project\Environment\CruiseControl\Project\app.config" "F:\Source\Project\Environment\Project" /Y /I /R
XCOPY "F:\Source\Project\Environment\CruiseControl\Project\My Project\Settings.Designer.vb" "F:\Source\Project\Environment\Project\My Project" /Y /I /R
XCOPY "F:\Source\Project\Environment\CruiseControl\Project\My Project\Settings.settings" "F:\Source\Project\Environment\Project\My Project" /Y /I /R
And lastly, here is Publish.bat
C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe /target:rebuild "F:\Source\Project\Environment\Project\Project.vbproj" /property:ApplicationRevision=%CCNetLabel% /property:AssemblyName="ProjectEnvironment" /property:PublishUrl="\\Server\bin\Project\Environment\\"
C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe /target:publish "F:\Source\Project\Environment\Project\Project.vbproj" /property:ApplicationVersion="1.0.0.%CCNetLabel%" /property:AssemblyVersion="1.0.0.%CCNetLabel%" /property:AssemblyName="ProjectEnvironment"
XCOPY "F:\Source\Project\Environment\Project\bin\Debug\app.publish" "F:\Binary\Project\Environment" /Y /I
XCOPY "F:\Source\Project\Environment\Project\bin\Debug\app.publish\Application Files" "F:\Binary\Project\Environment\Application Files" /Y /I /S
Like I said, it's probably not done the way that CruiseControl and MSBUILD developers had intended things to work, but it does work. If you need to get this working yesterday, it might be the solution you're looking for. Good luck!
I remember doing this last year for a ClickOnce project I was working on. I remember it taking me forever to figure out but here it is. What I wanted my scripts to do was to generate a different installer that pointed to our dev env and a different one for prod. Not only that but i needed it to inject the right versioning information so the existing clients would 'realize' there is a new version out there which is the whole point of clickOnce.
In this script you have to replace with your own server names etc. The trick is to save the publish.htm and project.publish file and inject the new version number based on the version that is provided to you by CC.NET.
Here is what my build script looked like:
<target name="deployProd">
<exec program="<framework_dir>\msbuild.exe" commandline="<project>/<project>.csproj /property:Configuration=PublishProd /property:ApplicationVersion=${build.label}.*;PublishUrl=\\<prod_location>\binups$\;InstallUrl=\\<prod_location>\binups$\;UpdateUrl=\\<prod_location>\binups$\;BootstrapperComponentsUrl=\\<prod_location>\prereqs$\ /target:publish"/>
<copy todir="<project>\bin\PublishProd\<project>.publish">
<fileset basedir=".">
<include name="publish.htm"/>
</fileset>
<filterchain>
<replacetokens>
<token key="CURRENT_VERSION" value="${build.label}"/>
</replacetokens>
</filterchain>
</copy>
</target>
Hope this helps
Just be able passing the ${CCNetLabel} in the CCNET.config msbuild task would be a great improvement.
You want to use the ClickOnce manifest generation tasks in msbuild. The process is a little long winded, so I am just going to point you to a couple of links. Here is the reference on msdn and a sample article to hopefully get you started.