Post Build events and NAnt build failures

Found a gotcha with NAnt and Visual Studio .NET 2003.
If you have specified a post-build event in the project properties (e.g. like a file copy operation - copy A.txt \executables) AND you have used the OutputDir attribute for the solution task in your NAnt build script (e.g. you want the built executables to go into another folder than the one specified in the proj properties) you'll run into build failures.

< solution configuration="${BuildConfig}" solutionfile="${ImportUtil_SlnPath}" outputDir="\executables" verbose="true">

The project will build correctly under the IDE but not under NAnt. This is because of the difference in current directories in both cases.

1. When run from the IDE, the path from which the postbuild batch is executed is [ProjectDir]\bin\debug (or release)
2. When run from NAnt, the path would be \executables (i.e. the OutputDir attribute value)
Hence the copy command can't find the source file and fails the build.

Lessons Learnt:

  • Post build events are not recommended - use NAnt build script as the single point where all such tasks are documented. Post build events are hidden inside property pages and hence are difficult for someone new to find out. This however means that the entire team makes a commitment to use Nant (bye bye IDE builds).
  • Do not use OutputDir attribute if you still use Pre/Post build events. :)

In the end I took option 2 to get my CI server back to Green

Finally my Pickaxe is here !!

As of this writing I have spent another 1.8K INR to get a techie book (The Pickaxe book) that I wanted to read. This because there is no Indian edition of this book available and I don't see anyone printing this here in the near future.I must confess I collect books that I like. I am just about to run out of space to keep em. Personally I hate reading online.. I normally don't go more than 4 pdf pages before my eyes hurt (although blogs are perfectly okay). There is something to holding a book in your hand and trying something out. Get stuck and automatically my hands reach for the book and I am already latching onto the relevant portion of the book. To do the same thing with a online book or html pages is pure pain (You need to know the particular html to initiate a Find on it.) Even with the plethora of online docs, I have old fashioned 'reference books' at arm's length.
But I find it very unsettling that I see very few people reading nowadays. In this field, where everything is on the move, the uncontrolled constant is change and the need is constant learning. There is a good chance that someone else has already been there and a book has been written. And if you procrastinate, there is a good chance that someone else isn't and you'd be picking up something like 'My Job went to India' (This is actually a book -
But here in Mumbai (commercial capital of the country) I need to wait for a month and pay thru my nose (no Amazon Discounts either) to get a book that was released in the US in 1999 i.e. six freaking years ago. At this rate, we'll always remain two steps behind and doing plumbing tasks with stone age tools. I'm of the opinion that the only way to learn something is to get your hands dirty. Nowadays thanks to the internet, the software requirements are easily met one way or the other :). But the books are turning out to be the real hurdles. As of today is the only option like freaking MTNL, a 'I'm the only one' 'take-it-or-leave-it' place.

But still, 2 chapters in, the book is making all this worthwhile. Thanks Dave, Andy and Chad for taking time out to help me find this gem of a language. Book Home Page

Next frontier in User Interfaces with Win Vista

Be afraid guys... very afraid. The following is claimed to be done by programmers who went from 0 experience to doing this in 6 weeks.
This is not a canned video playing but an actual CSharp app.

Essential .NET (Don Box + Chris Sells)

A bit terse but a treasure trove of .NET internal knowledge nonetheless. I finished the book last weekend. (Okay I cheated in the last 2 chapters). Security just went over my head and my intense passion for building heterogenous (COM, unmanaged and managed ) social (every module goes across the boundaries where the dragons be) systems (and pulling my hair out) led me to surf right over the last Interop chapter.The other chapters were quite enjoyable and I would recommend it to almost anyone, who is commited enough to unboxing the occasionally cryptic text. Also sometimes (read in the last 2 chapters), I felt that they were running out of pages and tried to stuff in as much as they could.
Assembly resolution, Interception and the CLR type system were real eye-openers. The figures in the book really help the prose.
All in all a great book.

What next?? I got another "Essential" book ( I love pain !) - Essential XML I'm gonna frag you too !!

Building your own Continuous Integration Server

The benefits of setting up a CIS are just too obvious

Setting up a Continuous Integration Server This is more of a personal Note to myself than a tutorial. You will not leave this post feeling that you know all the tools. You will have to spend time with their docs and get a little frustrated at times, but hey you live you learn.. You will need the following things.

Step 1. This is easy. Ensure that you have a working build by opening the workspace/solution file in the IDE and doing a complete build. Now we use this as a base for Step 2.
Step 2:Making an NAnt build file. Please unzip and READ THE DOCS folder in the nant zip. I found the docs really cool - nothing that makes you read and read and read and zzz. You can keep skimming thru the docs when you hit a dead end. Find the solution and forge ahead. The core concept is simple. The build file has tasks like a batch file has commands. But the tasks are inherently more powerful and configurable or else they wouldn't exist. Take a print of the NAnt tasks list - quick reference at a glance. So here's what I came up with..


<?xml version="1.0"?>
<!-- NAnt build script for a VS.NET solution
Gishu Sep 14, 2005.
Email: gishu<dot>pillai<at>gmail<dot>com -->
<project name="GC" default="debugBuild">
<property name="ReleaseOutputDir" value="bin\release" />
<property name="SolutionFilePath" value="source\GC.sln" />
<target name="clean" description="Cleans binaries folder">
<delete dir="${OutputDir}" verbose="true" failonerror="false"/>
<mkdir dir="${OutputDir}" failonerror="false" />
<target name="debugBuild">
<property name="OutputDir" value="bin\debug" />
<property name="BuildConfig" value="Debug" />
<call target="clean" failonError="false"/>
<call target="build"/>
<target name="build">
<exec program="..\GC_CheckOut.bat" />
<echo message="Source Checkout complete" />
<solution configuration="${BuildConfig}" solutionfile="${SolutionFilePath}" verbose="true" > <assemblyfolders>
<includes name="C:\Windows\Microsoft.NET\Framework\v1.1.4322\**" fromPath="true" /> </assemblyfolders>
</solution> </target> </project>

  • The .NET solution has a pesky hintpath property for framework DLLs. Running the solution task looks up the hardcoded HintPath value and fails. To go around this, you need to add an AssemblyFolders element to the solution task, with the path to the Framework installation on the current machine. This can be a property/constant defined at the top of the build file.
  • Next, another thing that I overlooked in my exuberance is that NAnt.exe.config take framework 1.0 as the default. Change this is you are using Framework 1.1 or else meet Mr. Build Failure. When I found this, I felt specially stupid since I had done the same thing on my last attempt at home. This time I'm gonna DOCUMENT IT HERE!!!.
  • Use the new (and uber cool) solution task. It does not require the IDE and blah blah to be installed. What it does is that it parses the solution file and invokes csc ( long live the command line ) after resolving references. Now ain't that sweet ? It doesn't use devenv - less resources required and faster. I read this from DevX.

Step 3: Meet Cruise Control.NET CruiseControl is another Rad tool which will help complete our Continuous Integration Server. Configure your CruiseControl.NET Server: You need to make a ccnet.config file to make your server do something useful. Start with the \Doc\CCNET\CruiseControl.NET Server.html under the CC installed directory. You will need to write your specific sourcecontrol block, based on what you actually use. G TIP This tool will only detect an update to the SourceControl Server and then give you a callback. You have to write a script to check out the changes. CC won't do it for you. This was something I learned the hard way. So you need to write a script that will checkout the latest source. This will depend on exactly what you use - I have tried Subversion and StarTeam. Both would be different scripts - see their command line documentation for details. I have built myself a batch file. There I go putting my foot in my mouth. The Subversion block did not have this option but I now see that Starteam sourcecontrol block has a [autoGetSource]true[/autoGetSource] entry. I'll try that out later and update this post. For now I'll stick to my batch file (which I have verified works from the prompt).

Listing: Sample CC config file

<!-- My Second CruiseControl Config File
Gishu Sep 14, 2005.
Email: gishu<dot>pillai<at>gmail<dot>com -->
<project name="GC">
<sourcecontrol type="starteam">
<executable>c:\Program Files\Starbase\StarTeam 5.4\stcmd.exe</executable>

<username>buildGuy</username> <password>buildPwd</password>
<host>XX.XX.XX.XXX</host> <port>50000</port>
</nant> </tasks>
<triggers> <intervalTrigger seconds="1800" buildCondition="ForceBuild"/> </triggers> <publishers> <xmllogger><logDir>E:\Program Files\CruiseControl.NET\server\GCLogs</logDir></xmllogger> </publishers>
</project> </cruisecontrol>

Copy the ccnet.config file to your CruiseControl.Net\Server directory. Ensure that Nant is on your PATH EnvVar so that CC can find it. Now pray to your favourite God and double-click the ccnet.exe file in the server directory. This should start the CC Server. (SP2 might try to throw a spanner in the works. Click on Unblock).


  • In case of people like me, this generally blows up. So what you do is start a command prompt and start the exe from within the command window. This gives you a chance to look at what blew up. Common things - incorrect paths, locked log files (Stop any running servers first), etc.Ok looks like I got my StarTeam folder project and view names wrong. Backspace Backspace Type Type. That’s it !

Now I can open my web dashboard http://localhost/ccnet to view a whole lot of things on a web page, totally FREE. Not an iota of effort put in. That’s the kinda of thing I like. I had a lotta fun doing this and this will help me have a lot of fun in the future rather than sit here verifying builds. I have got better things to do.. If you have any issues/suggestions or things that you feel I should know, post a comment here. I’ll try my best to get back.. Ciao!


Source control servers across WANs rob you of most of the joy with a CIS. E.g. My experiment showed that a project which takes around 17 secs to build from the command prompt with an NAnt script, will take ~11 mins! What the @#%^!!! Allmost all the time is spent in network operations for the SourceControl app (Starteam here), even when checking out only the changes. Still I feel that the benefits justify the time spent even though you have to wait for some time to see the green light. Another excuse for a break :)

Starteam is absolutely horrendous. If you have ST as the source control and it is also across a WAN, please stick with doing all this manually. Take this from me..

Machine Name : BABYBOX

Here it is the new one in my stable. I present my new second machine. This was a near impulse buy. Plan to buy time of under a week. My old machine is sick so I thought that there is no use flogging a dead horse.
Constraints = Money. I had decided that 10K INR is the max I would go. I ended just breaching the limit by a few hundreds.
The new hardware list
  • AMD Sempron 2500+
  • ASUS K8S-MX mobo (got onboard sound, video and LAN)
  • 256 MB 400MHz RAM 1200 INR
  • Sony DVD ROM drive 1500 INR
  • Mini Cabinet 1550 INR

The things I reused list

  • Monitor
  • Keyboard+Mouse
  • DialUp Modem
  • Floppy Drive
  • a 10 Gig HDD

The motherboard supports 6.1 sound and 8 usb ports (fine print - need to buy additional module for going above normal 2 spk sound and 4 USB ports). I have it on my home lan and it is a dream to work on.

The AMD Sempron 2500+ CPU 1.4 GHz has a x64 logo - is this a 64 bit CPU ??? Performance wise it's quite okay. Prior to installing Norton and Win2K, everything was fast :)) I had heard that AMDs run hotter than Intel in the past but this thing blows cold air out like an AC. I do not know the reason for this ... good ventilation - air not getting time to heat up ? nothing heating up ?

The cabinet is quite small at the cost of limiting any expansion (can only fit in 1 CD, floppy and HDD). But then this is my second machine that I wouldn't be using for gaming. So doesn't matter. It's kinda cute.

The ASUS Mobo is sweet. A good board with everything nicely color coded to prevent goofups. Nice manuals. I had to flash my BIOS to get it to recognize my CPU (seems it's a new release). Went in with all fingers crossed but it turned out okay due to the ASUS EZ update utility. Norton 2005 is bundled.

My Wish to own an AMD comes true.


Under the hood of BABYBOX

Essential Interception using Contexts in .NET

This chapter is a result of my tinkering with the Advanced methods chapter of Essential .NET (Don Box and Chris Sells). This chapter is one of my favourites in the book.
Task : Boost thread priority temporarily to a level (specified by the component type). Keep in mind that we want to provide this as an Aspect of the class. The class authors should not have to write any special code or use convoluted/arcane ways to instantiate objects.
This is the example taken in the book. We can intercept calls and provide any pre/post processing as needed. Some of it is not well-documented in .NET. But I loved it nonetheless. This post is to make sure I don't forget the entire load and an attempt to unbox Don Box ( had to let that out of my system).

Keep in mind that any method call can be represented as a Message. System.Runtime.Remoting.Messaging contains IMessage, IMethodMessage, IMethodCallMessage, IMethodReturnMessage, IConstructionCallMessage and IConstructionReturnMessage. (Look up MSDN for more on these classes :)

Option A: The simple but slightly tedious way is to define a proxy class and a Factory method in the required class. This can be seen in the source file Interception1.cs. The essence here is the System.Runtime.Remoting.Proxies.RealProxy class.

  1. So we derive from this class e.g. PriorityProxy to wrap our target class. The target class defines a factory (public static) method like CreateInstance() to have a chance to intercept creation. And obviously, hide the ctor. Now in this method, we create our ProxyObject with a new instance of our target class. We now return a transparent proxy ( a class that mocks everything in our target class ) by returning obProxyObj.GetTransparentProxy(). This is what the calling code gets back.. a devious imposter !
  2. Next: The prime method RealProxy.Invoke() takes and returns an IMessage implementation. Any method call to our transparent proxy is delegated to RealProxy.Invoke(). We can do nothing and call the method via RemotingServices.ExecuteMessage(target, IMethodCallMessage). But we did not jump thru all these hoops to do nothing. Before and After this call lie endless possibilities. E.g. Here we can bump the Thread Priority as Pre-Op and restore it after as Post-Op code.
    Note to call RemotingServices.ExecuteMessage, our target class must derive from MarshalByRef object. This looks restrictive but I do not know of another way to "Call a method" on a target class

So there we have it. But we don't wanna write factory methods (and raise suspicion) so there has to be a more transparent method. And it turns out there is, we can use a special attribute (System.Runtime.Remoting.Proxies.ProxyAttribute) to do this. See Attribute.cs
Derive an Attribute class from ProxyAttribute e.g. PriorityProxyAttribute.

  1. The magic here is that if a class derives from System.ContextBoundObject and it is decorated with a ProxyAttribute, then as Don Box says, the CLR does a dance for you to intercept creation. On a "new", The CLR will first create the ProxyAttribute and call ProxyAttribute.CreateInstance(Type). The default implementation creates the type for you. You cannot call new here as it will trigger the same thing all over again. So here we can create our PriorityProxy here and return the transparent proxy. This eliminates the need for a factory method. The client just does a simple new to instantiate!

So is that all ? Not at all. We're just getting warmed up. For more control (read control-freaky control), we have Contexts and sinks (not the kitchen variety but message sinks). Contexts are logical divisions within an Appdomain analogous to the relationship between AppDomains and Processes. Deriving from ContextBoundObject means that the object is attached to a specific Context i.e. not "Context-Agile". So let's dive into this. For Source, see Contexts.cs

  1. First we decorate our target class with an Attribute that implements IContextAttribute. System.Runtime.Remoting.Contexts.IContextAttribute defines two methods

    void GetPropertiesForNewContext(IConstructionCallMessage msg);
    bool IsContextOK(Context ctx, IConstructionCallMessage msg);

    On a new on our ContextBound type, The CLR will find all context attributes for this class and begin Pass 1. Here it will inquire IsContextOK for each attribute i.e. is the current context fine by you, O mighty context attribute? The context attribute can perform a check and say Nay by returning false. In my example, I call GetProperty on the context to check if the context has a property "ThreadPriority" AND it matches the requested priority. If any one fails, I return false.
    This lets the CLR know that a new context needs to be created. It does so and then begins Pass 2. This time it will call upon GetPropertiesForNewContext(). Each attribute is given a chance to add "context properties" to the new context. This is it's reason for existence. A context property implements System.Runtime.Remoting.Contexts.IContextProperty

    void Freeze(Context newContext);
    bool IsNewContextOK(Context newCtx);
    string Name { get; }

    The third member defines the name of the context property (e.g. "ThreadPriority"). The second member is there to handle conflicts. A type may have multiple context attributes, each adding properties that may have conflicting requirements. So a property can return false to cancel instantiation and throw an exception. Our amiable property return true.. it can get along with any one.
  2. Ok but where is the interception ? For that we now bring in the heavy artillery, Message Sinks. A context property has the ability to add sinks in the message chain. There are four types of sinks
    1. Server Context Sink
    2. Object Sink
    3. ClientContext Sink
    4. Envoy Sink
    All other types other than the Object Sink will be covered in a later post (all my constraints permitting). To add an Object Sink, the property needs to implement System.Runtime.Remoting.Contexts.IContributeObjectSink. This interface has a single method, which returns the MessageSink to be added. (We add our PrioritySink in our property PriorityContextProp). So there we have it, our control point.
    Our PrioritySink is a Message sink, why ? because it derives from IMessageSink.

    IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink);
    IMessage SyncProcessMessage(IMessage msg);
    IMessageSink NextSink { get; }

    Our focus here would be on SyncProcessMessage. On a (synchronous) method call, this method would be called on each sink (a chain may be present). Our implementation of this method would boost the thread priority before calling SyncProcessMessage on the next sink in the chain. Then it restores the old priority.

To use this aspect, we can define any class

public class Amadeus : ContextBoundObject
public void ComposeAGermanOpera()
Logger.LogMessage(" Amadeus.ComposeAGermanOpera() ");
Console.WriteLine("Mozart goes to work!!!");

Object usage

Amadeus Mozart = new Amadeus();
Logger.LogMessage("Commission Mozart.");
Logger.LogMessage("Mozart - Out.");

Here is the output due to some logging code (mainly for inspection purposes)

Thread-2 Context-0 Priority-Normal : Commission Mozart.
Thread-2 Context-1 Priority-Normal : IContributeObjectSink.GetObjectSink()
PrioritySink.SyncProcessMessage (ObjectSink impl) Obe-wan boost my force!
Thread-2 Context-1 Priority-AboveNormal : Amadeus.ComposeAGermanOpera()
Mozart goes to work !!!
PrioritySink.SyncProcessMessage (ObjectSink impl) Obe-wan boost my force!
Thread-2 Context-1 Priority-AboveNormal : Amadeus.ComposeAGermanOpera()
Mozart goes to work !!!
Thread-2 Context-0 Priority-Normal : Mozart - Out.

Fantastic – excuse me while I pat myself on the back again ! From the object usage, do you suspect anything going on behind the scenes ?

Amadeus Mozart = new Amadeus();

Without the logging, everything would be like Magic. All method calls to Amadeus instances are on Nitro!! To quote The Ghost who walks ‘Everything’s simple when you know how’. There you have it. No more interfaces I promise..

Essential .NET – Don Box and Chris Sells. – Juval Lowy

For the source file I am trying out a free hosting site - Hope this works! file name: file size: 12439 bytes File number: 00080238 file link:
Everything written here is based on my understanding, which is nothing to write home about. Use your better judgment... FINE PRINT

Enabling AutoComplete at Win2K Command Prompt

I just copied the steps from Thank you Venkat Sankar, u great surfer on office time !!!!

I don't know why this is not turned on by default. Who in their right minds would rather type out complete paths ?

• Type Regedit and OK,
• Find HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor,
• In the right pane of Regedit, double click the 'CompletionChar' DWORD value,
• Type 9 click OK,
• Close Regedit,