2008/03/27

Getting info back out of a custom MSBuild Task



So I am working on getting some build automation and such. Unfortunatly, my client is running Visual Source Safe (how I miss Team Foundation Server). So I am tasked with getting the latest code out of VSS, build numerous configurations of our solutions ensuring that *.config are set to reflect the envirounment required for each configuration to be built. After I get the code, I want to label it so if we need to go back and rebuild version x.y.z we can grab its label.




In TFS, I would just let the vanilla installation and TeamBuild.targets deal with coming up with a label number. But again, I gots no TFS. So I am going to generate a label based on the date and use MSBuild Community Tasks (available at http://msbuildtasks.tigris.org/) to handle the communication to VSS.




So how do you get the date formatted the way you want? Well, there is the easy System.DateTime.ToString(string format), right? All you have to do to get to this functionality is to write an MSBuild custom task.




Enough talk, on to the code. You start by creating a new class library project and adding references to Microsoft.Build.Framework and Microsoft.Build.Utilities.





Now you need to start building your class. Something like this should do the trick:



using System;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
namespace MSBuilding
{
public class GetDateTime : Task
{
DateTime _now;
string _format = string.Empty;
///
/// The format string to be passed to DateTime.ToString method
///

[Required]
public string Format
{
set { this._format = value; }
}
///
/// This is the TaskParameter that is returned.
///

[Output]
public string ReturnValue
{
get { return _now.ToString(_format); }
}
///
/// Required to implement the Microsoft.Build.Utilities abstract class.
///

///
public override bool Execute()
{
bool result = true;
try
{
_now = DateTime.Now;
}
catch (Exception ex)
{
//something failed set the result to false and log the Exception
result = false;
bool showStackTrace = true;
Log.LogErrorFromException(ex, showStackTrace);
}
return result;
}
}
}


Here's what's happening. I'm declaring the class GetDateTime and having it inherit from Microsoft.Build.Utilities.Task Then I'm setting up some class-level variables for _format and _now. Then I am setting a required property for Format this ensures that a format is passed in from the MSBuild project. Also, I am putting minmal logic into the Execute method as this class is really doing minimal.


To get info back out of the task, you need some properties with the [Output] attribute tagged onto them. In the case of this class, we have one property, ReturnValue.


Now all we have to do is write up a simple proj file and invoke the task we wrote. A simple, single target project is good enough for testing:

<?xml version="1.0" encoding="utf-8" ?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Test">
<UsingTask AssemblyFile="MSBuilding.dll" TaskName="MSBuilding.GetDateTime"/>
<Target Name="Test">
<GetDateTime
Format="yyyyMMdd_HHmmss_ff">
<Output TaskParameter="ReturnValue" PropertyName="MyTime"/>
</GetDateTime>
<Message Text="$(MyTime)"/>
</Target>
</Project>
Now we just call MSBuild.exe passing our proj file as the only argument.


That's about it. Look for more MSBuild goodness as I get time.

2008/03/25

ADO.Net Data Services: Astoria

Steve Horn has some great information to answer the burning questions about Astoria.

A brief overview of what is to come

In my "spare time" I'll be posting any info that has been helpful in blasting away roadblocks in my development projects in topics consisting of Winform development, ASP.Net, Team Foundation Server, and SQL Server.

I make no promises or guarantees on the content or frequency, so use at your own risk.

Comments