Invoking MSBUILD from Inside an App

So I have created some custom MSBUILD tasks (to deploy SQLCLR assemblies). They work fine when I execute them from command line: msbuild /t:taskname project_file.

However when I try and execute from inside an application by using the Engine.BuildProjectFile, I can't get it to work. That's not the main problem as at the moment I am explicitly sending in params which should make it fail. The weird part is that I can not get any output back. I have registered a FileLogger, and the Engine.BuildProjectFile returns failure, but the lgger file is empty. If I supply an incorrect task assembly, I do get an error back in my log file. It si when the actual task fails that I don't get any results back.

Any ideas?

Niels

[731 byte] By [nielsb] at [2007-12-17]
# 1
Hi Niels,

Can you post a code snippet of how you are calling the MSBuild object model methods? Keep in mind the difference between a "target" and a "task". A "task", of course, is the class that you implemented as a plugin to the build process. A "target" is the piece of XML in the project file or .TARGETS file that actually invokes the task. The /t: switch on the msbuild.exe command-line only allows you to execute "targets". Some things to check:

1.) When you call Engine.BuildProjectFile, are you calling the overload that allows you to specify the target name?

2.) When you register the FileLogger, are you passing in the log file name? (I assume yes, since you apparently have gotten the file logger to work in other circumstances.)

3.) Assuming you can get the FileLogger working the way you want, you might try logging with a higher verbosity, so that you can see exactly what is going on in the build process. You can do this by setting FileLogger.Verbosity after constructing it.

4.) Make sure your task implementation is actually logging an error when it fails. It can do this by calling one of the Log.LogError(...) overloads.

Hope this helps.

--Rajeev

RajeevGoelmsft at 2007-9-9 > top of Msdn Tech,Visual Studio,Visual Studio MSBuild...
# 2
Rajeev,

Thanks for the reply. I got it to work (kind of), but I don't know why. There was initially an issue with the build engine not finding my task dll. That was logged properly in my logger.

I then changed the project file to use the AssemblyFile property and it was at this stage that it failed but I did not receive any errors in the log file. I believe the problem was that I at that stage had both an AssemblyName as well as an AssemblyFile property in my project file. 'cause whan I took out the AssemblyName property and only had AssemblyFile it worked OK.

So, a couple of follow-up questions;
1. What is the preffered way to define the bin path for the Engine. My application that uses the Engine will be installed on various computers so the path can not be hard coded. It will also be installed on both 32-bit as well as 64-bit, and subsequently use both the 32-bit as well as 64-bit version of the framework.
2. Going back to the problem with not finding the task dll; I would have assumed that having the task dll on the PATH would take care of that, but apparently not. What are the best practices for this?

Niels

nielsb at 2007-9-9 > top of Msdn Tech,Visual Studio,Visual Studio MSBuild...
# 3
1. Regarding the BinPath that is required to be passed into the Engine, basically you need to locate the version of the .NET Framework that contains the MSBuild .TARGETS and task assemblies that you wish to use. I can think of a couple approaches to this, but there are probably others depending on your scenario:

a. If it is guaranteed that your application will only be run on machines that have Visual Studio 2005 installed, then you can look up this registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\MSBuild

Under this key, there is a value called "MSBuildBinPath"; just read that out and pass it into Engine.BinPath.

b. You could also look up the following registry key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework

There is a value called "InstallRoot" which will take you to the base directory of .NET Framework installations, and from there, you have to find the subdirectory that corresponds to the version you want to use. For example, you might just search for all subdirectories that start with "v2", and just pick the largest version number from there.

2. No, MSBuild does not search the PATH for .NET assemblies, including task assemblies. This is not the recommended approach in .NET. The .NET way is to either install dependent assemblies to the GAC, place them in the directory of the .EXE, or specify an explicit path to the dependent assembly. In terms of your task assembly, I would recommend either GAC'ing it and using the "AssemblyName" attribute, or placing it in an arbitrary directory and using the "AssemblyFile" attribute. It is considered an error to specify both AssemblyName and AssemblyFile, but I'm not sure why your logger didn't receive the appropriate error event for this. When you just run msbuild.exe from the command-line, do you get an error?

--Rajeev

RajeevGoelmsft at 2007-9-9 > top of Msdn Tech,Visual Studio,Visual Studio MSBuild...
# 4
2. No, MSBuild does not search the PATH for .NET assemblies, including task assemblies. This is not the recommended approach in .NET. The .NET way is to either install dependent assemblies to the GAC, place them in the directory of the .EXE, or specify an explicit path to the dependent assembly. In terms of your task assembly, I would recommend either GAC'ing it and using the "AssemblyName" attribute, or placing it in an arbitrary directory and using the "AssemblyFile" attribute. It is considered an error to specify both AssemblyName and AssemblyFile, but I'm not sure why your logger didn't receive the appropriate error event for this. When you just run msbuild.exe from the command-line, do you get an error?

As regarding the question about why some errors didn't show - forget that. I had done something stupid.

About not finding the task dll: Yes, I am aware of the .NET's way of resolving assemblies. However, when I run BuildEngine.BuildProjectFile(some_file), where does the build engine execute from? I assume the build engine is MSBUILD.exe, and it executes from the BinPath; in that case I don't understand why the task dll can not be found - as I have my task dll in the same directory as MSBUILD.exe. Furthermore, when I run MSBUILD from command line directly, it finds my task dll.

Niels

nielsb at 2007-9-9 > top of Msdn Tech,Visual Studio,Visual Studio MSBuild...
# 5

When you are calling BuildEngine.BuildProjectFile yourself, then MSBUILD.EXE is not involved in any way whatsoever, and therefore placing your task assembly in the directory of MSBUILD.EXE won't help. You would need to place your task assembly in the directory of the running .EXE, whatever that is. Presumably you have your own .EXE that you're running here.

--Rajeev

RajeevGoelmsft at 2007-9-9 > top of Msdn Tech,Visual Studio,Visual Studio MSBuild...
# 6

Ah - OK, that explains it. Thanks a lot!!

Niels

nielsb at 2007-9-9 > top of Msdn Tech,Visual Studio,Visual Studio MSBuild...

Visual Studio

Site Classified