Custom MSBuild task with dependencies - msbuild

I have written an MSBuild task that makes use of third-party assemblies.
When I use the task in my project, MSBuild complains that it can't load the third-party assemblies (not surprisingly).
Where should I place the third-party assemblies so that they are available to MSBuild. I tried adding project references to them without success.

I'm not sure if I expressed my problem very well, but now I've found the solution.
In my .proj file, I reference my custom task with the following syntax...
<UsingTask AssemblyFile="..\lib\MyCompany.MSBuild\MyCompany.MSBuild.dll" TaskName="CreateDatabase" />
My CreateDatabase task relies on various 3rd-party assemblies. However, some of these are only referenced via reflection, so weren't included by default in the folder "..\lib\MyCompany.MSBuild".
I had been trying to get the task to work by placing the required assemblies in the same directory as the .proj file invoking the task.
However, what I should have been doing was putting the assemblies in the referenced task directory "..\lib\MyCompany.MSBuild\".
Simple!

You could add them to the GAC (Global Assemby Cache). This only works if it is strongly named.
You could also make sure that you have marked them with copy local = true when you added the reference in the project.

Related

ClickOnce app built via Jenkins throwing CS1704 - An assembly with the same simple name {whatever} has already been imported

I have a winforms app, which is deployed via click-once publishing.
Assuming my tests are correct, the only way to have this same app installed more than once in the same machine, is the each publish be made for a different Assembly Name.
My problem is that I am running the msbuild via jenkins, and, to accomplish the above, I would add /p:AssemblyName={whatever}, which will rename all assemblies generated by the build to this same {whatever} value. If the output of my build is 1 exe and 5 dlls, all 6 files will be named {whatever}.
Which in turn raises CS1704: An assembly with the same simple name {whatever} has already been imported.
Is the only way out of this to perform all csc.exe calls that msbuild generates, myself, and see if I can set different assembly names per project ?
Or are there other ways to solve this ?
The problem here is that every property passed to MSBuild as a command line argument is considered a global property and will override the property on all projects built in that invocation. The solution is to introduce an intermediate property that only the "main" project consumes.
Edit the app's csproj file to include this (in the place where AssemblyName is already defined - assuming here that WindowsFormsApp1 is the name of the application):
<AssemblyName>WindowsFormsApp1</AssemblyName>
<AssemblyName Condition="'$(OverrideAssemblyName)' != ''">$(OverrideAssemblyName)</AssemblyName>
you can then use the msbuild commands using /p:OverrideAssemblyName=AnotherName without creating conflicting assembly names on referenced libraries. The property is still defined globally, but only one project consumes it.

How can I set the build destination in Team Services for WIX

I am using Windows installer xml and now my project moves to Team Services.
However, my Paths wont work anymore and I need to update my setup.
On the local build machine I used this hardlink: C:\Projects\Solution\Project\bin\Release\Assembly.dll
My Question: What is the best way to build 4 projects and then run a 5th project, which uses the assemblies in the bin/release directory?
Add a reference to the project and then use $(var.Project.TargetPath) instead of the hardlink (or $(var.Project.TargetDir)Assembly.dll). The references will add dependencies on those projects to the wixproj which means they all must be build before the wixproj so all the binaries will exist. All the projects should be included in the same solution as the wixproj.
Here's a resource for all the automatically defined compile time variables you can use http://wixtoolset.org/documentation/manual/v3/votive/votive_project_references.html
Alternatively if you can't do it this way you can define the variables in the <DefineConstants> of the wixproj. It would be something like "ProjectDir=$(MSBuildThisFileDirectory)..\Project\bin\Release\" and then in your wix component where you are using the SourceDir hardlink you would use SourceDir=$(var.ProjectDir)Assembly.dll
All of this stuff is taking advantage of MSBuild. It takes a long time to wrap your head around how MSBuild works but it is definitely worth it if you will be using Visual Studio to build all your projects.

MSBuild UsingTask and resolving references

I am using NuGet to pull in YUICompressor.NET.MSBuild, which in turn pulls in YUICompressor.NET and EcmaScript.Net.
It also adds references to all three DLLs in my web project.
I can then add the UsingTask reference like this:
<UsingTask TaskName="CssCompressorTask" AssemblyFile="$(SolutionDir)\packages\YUICompressor.NET.MSBuild.2.3.0.0\lib\NET20\Yahoo.Yui.Compressor.Build.MsBuild.dll" />
And then use the task to compress my Javascript/CSS in an AfterBuild target
However, I don't want to have to reference these DLLs in my web project (as they are not actually part of what I ship)... but when I remove the references, then CssCompressorTask can no longer find the other two dependent DLLs (they are in different folders off the /packages folder - it works ok if they are alongside Yahoo.Yui.Compressor.Build.MsBuild.dll)
Believe it or not, I have spent hours trying to get the dependencies to resolve:
First I tried to modify AssemblySearchPaths to include all the other /packages subfolders, as here:
https://github.com/BenPhegan/NuGetAutoTransitiveDependencies
This didn't work, so I tried to create an inline assembly resolver, as here:
MSBuild UsingTask Resolve References
This doesn't work either. At the moment, I am thinking the only choice I have is to get the dependent DLLs alongside the UsingTask dll, one way or another... but this feels like my MSBuild foo is failing me :/
Any ideas much appreciated! Thanks.
I needed my custom task to use the JSON API (NewtonSoft). MSBuild did not load the external dll until I ran gacutil /i [path to dll].
Ok, v2.4.0.0+ now include the DLLs

Can MSBuild ignore a project reference? (BuildProjectReferences doesn't work)

I am trying to make a build script for a .NET solution which consists of several c# projects and one custom project. The custom project can be build by devenv but msbuild chokes on it.
I would like MSBuild to ignore the custom project because I'm already building it with an Exec task. I actually need MSBuild to not even open the custom .proj file because it's in JSON format and thus causes MSBuild to crash out.
The /BuildProjectReferences=false switch doesn't work. MSBuild still tries to read the custom project file. Is there any way around this?
This question stemmed from a project which had a SilverFrost Fortran project alongside several c# class libraries. The solution would only compile using devenv. Msbuild would throw an error on the Fortran project because it doesn't use the standard .csproj format.
Even with /BuildProjectReferences=false, msbuild would try to read the Fortran project and throw an error. The workaround I discovered was to wrap the msbuild task in an nant task which does the following:
Invokes the Fortran command line compiler
Removes all references to the Fortran project from other .csproj projects using the xmlpoke task
Replaces said references with a direct dll reference to the Fortran compiler output
Invokes Msbuild on the modified solution
Instead of building your solution once by MSBuild, try to build each project one by one. In this case, you can ignore the desired project. You can also define your own "Exec"-based build in this new script.
In your project that uses the custom project, can you right click on the Project Dependencies and remove the custom project from the list? You can refer to the custom project's binary output instead.

MSBuild doesn't pick up references of the referenced project

I bumped into a strange situation with MSBuild just now. There's a solution which has three projects: LibX, LibY and Exe. Exe references LibX. LibX in its turn references LibY, has some content files, and also references to a third-party library (several pre-built assemblies installed in both GAC and local lib folder). The third-party library is marked as "Copy Local" ("private") and appears in the output of the LibX project, as the LibY's output and LibX's content files do. Now, Exe project's output has LibX project output, content files of the LibX project, LibY project output (coming from LibX), but NO third-party library's assemblies.
Now I worked this around by referencing the third-party library directly in Exe project, but I don't feel this is a "right" solution.
Anyone had this problem before?
There is a difference in behavior when building with MSBuild (i.e. command line, TFS Build and other tools) compared to building with Visual Studio. The secondary references are not included in the references variable sent into MSBuild compile tasks.
There are several extension points provided by MSBuild to change how references are to be resolved. I have successfully used AfterResolveReference to fix this issue for some of my projects - I have posted more info about the background on my blog.
The workaround is to add the following code into you vbproj or csproj files
<Target Name="AfterResolveReferences">
<!-- Redefine referencepath to add dependencyies-->
<ItemGroup>
<ReferencePath Include="#(ReferenceDependencyPaths)">
</ReferencePath>
</ItemGroup>
</Target>
Microsoft has stated that this is a won't fix on Connect
You can actually go into the Microsoft.CSharp.targets or Microsoft.VisualBasic.targets file (located in the framework directory, usually C:\Windows\Microsoft.NET\Framework\v3.5) and modify the csc or vbc task parameters to include additional reference dependencies. In the file (VB targets, line 166; C# targets, line 164) change:\
References="#(ReferencePath)"
to
References="#(ReferencePath);#(ReferenceDependencyPaths)"
This might cause other issues depending on how complicated things are and it may play tricks with the Visual Studio inproc compiler, but it's the only way to do it in MSBuild that I've found.
josant's answer almost worked for me; I kept getting an error in Visual Studio when I tried that:
A problem occurred while trying to set the "References" parameter for the IDE's in-process compiler. Error HRESULT E_FAIL has been returned from a call to a COM component
The solution to my problem was to put a condition on the ItemGroup, like this:
<Target Name="AfterResolveReferences">
<!-- Redefine referencepath to add dependencies-->
<ItemGroup Condition=" '$(BuildingInsideVisualStudio)' != 'true' ">
<ReferencePath Include="#(ReferenceDependencyPaths)"></ReferencePath>
</ItemGroup>
</Target>
That caused Visual Studio to ignore the reference change completely, and the build works fine locally and on the build server.
Yes, I've had that problem, too. Though I'd love to say otherwise, I believe you must include all transitive dependencies as references in your build file.
I've combined Alex Yakunin's solution with one that will also copy native dll's.
The AfterResolveReferences method fails if you've got a directed graph not a tree with a "trying to deploy different copies of the dll" error. (cf. How to configure msbuild/MSVC to deploy dependent files of dependent assemblies)