December 2007

It's been an amazing year of ups and downs. Our family is fortunate that we've had many more high's then lows and sometimes I lose sight of that. The new year is a great time to reflect on the past year and to look forward to the new year. I've been forming this post in my mind for a while now. Thinking back to everything our family was able to accomplish. And if you're interested I'd like to walk you down our journey of 2007. In January I was working at a place that I didn't feel comfortable in. It was stressful because I just wasn't happy with where I was, and where I was going. I was a below average software dev and didn't know which direction I wanted to go or whether I wanted to seriously take on software as my craft. I eventually decided that I was unhappy because I didn't feel that my skill sets were up to par and that I really wanted to jump into this exciting world we call .NET development. The world of C and VB6 quickly lost it's charm and a dispute with a co-worker about use of racial slurs was the end for me. I developed the fire in my belly to get better. I began the first of 5 courses at SAIT to work towards a C# programming certificate. I started heavily reading blogs, in particular JP's. I have to say that his passion for development was so contagious that I felt I truly could excel at software development and I was having fun while doing it. As I finished off course textbooks one after another I came across a post by Justice Gray where he planned to read several books in a span of several weeks. I looked up JP's book list and made it a goal to devour every book on that list. I haven't finished them all but I have read quite a few of them now. In February I started work at MediaLogic as a full fledged C# developer. I'm fortunate that they saw potential in me and took me on as a junior to help me grow. The environment here at MediaLogic allowed me to flourish in ways that I never imagined possible. I also started to listen to more and more podcasts at this time. It became a ritual to either listen to pod casts or read books while riding the bus to and from downtown every day.
In April, I attended that Calgary Code Camp. I was looking through my notebook the other day and found a slip of paper that had a schedule for presentations that I wanted to attend at the Calgary Code Camp in April. The slip had presentations by Terry Thibodeau, James Kovacs, Jean-Paul S. Boodhoo, Steven Rockarts, and Donald Belcham. As I read over the slip I realized that at the time I wrote on the piece of paper and at the time I sat through they're presentations I never thought I would be able to actually get to know some of these people or even be able to fully understand some of the content they delivered. I've now had the privilege of shaking hands with many of the above mentioned names and I think (I think...) some of them may even know me by name. In August, I stared at what I thought would be a record low bank balance. I remember feeling quite scared, feeling like I had no control and was quite worried about how I would be able to keep our family a float. I remember a lot of sleepless nights, which I now realized helped me excel even faster. Failure was not an option.
In September, I read a couple of books by Robin Sharma and attended a live presentation by him. I remember thinking that I thought he would be taller. But it seems some of the greatest minds make up in thought for what they lack in height.
I also remember staring that the ThoughtWorks web site for weeks reading through everything that I could, contemplating about whether I was ready or whether I would make the cut. I read about Martin Fowler and about a company who's values were inline with my own and offered opportunities that I could only dream of. I eventually decided to take the plunge and apply, I figured if I didn't have what it takes at least I want to find out what I need to focus on.
In October, I spent the month heavily studying towards my first MCTS exam. I travelled up to Edmonton and shook hands and had lunch with the legendary Justice Gray, where he introduced me to several other passionate developers up in the Edmonton community. In November, we celebrated my daughters first birth day. I completed the first exam towards an MCTS designation, I attended the infamous week long Nothin' But .NET Boot Camp, had my in office interview at ThoughtWorks, began my fifth and final course at SAIT, and caught the very last presentation at the Alberta Tech Festival by Gerard Meszaros. In December, we celebrated a wonderful Christmas filled with family and joy. We hit a new record low bank balance but realized that it might be the last for a while when I received an offer for full time employment at ThoughtWorks. The new year will no doubt be one of the most challenging ones so far. Bring it on 2008!

So another thought that came to mind was the concept of how to switch views in a winforms application. Bare with me because these are only thought so far and I have yet to read about the actual "Application Controller" pattern in PoEAA.
I've been reading a book on WinForms lately by Chris Sells, the name evades me at the moment but I promise to give you the name in the future. And it tells about the ApplicationContext and how it works and how you can access it.
If you take a look at the overloads for the "Application.Run()" method you'll find one that accepts an ApplicationContext. When you choose the overload that accepts a Form it creates an application context and registers for the form closing event which is when it call Application.Exit().
If you can access the context then you can access the start up form, and if you need to switch user controls on the main form you can try to access the application context to do so. Here's my 30 second brain dump on potentially how this could work... (Warning... I have yet to fully implement this!)

    public class ApplicationController
    {
        private static System.Windows.Forms.ApplicationContext _context;
        private readonly IScreenRegistry registry;

        public ApplicationController( IScreenRegistry registry )
        {
            this.registry = registry;
        }

        public static void Begin( )
        {
            Application.EnableVisualStyles( );
            Application.SetCompatibleTextRenderingDefault( false );
            _context = new System.Windows.Forms.ApplicationContext( new Form1( ) );
            Application.Run( _context );
        }

        public void Render( IScreen screen )
        {
            _context.MainForm.Controls.Add( registry.FindFor( screen ) );
        }
    }

Main then becomes an empty shell that delegates to the application controller, when types in the system need to render a new view it can call upon the ApplicationController to take care of that by calling it's Render method and passing in the screen to display. The application controller can then leverage registry to find the user control that's registered for the screen.

Hey, if anyone knows a good book on WinForms patterns of even UI patterns I'd love to hear about it!

Source:

So i was digging through some old posts of Adam's and found one where he's pointing to article on MSDN on the new language features in C# 3.0. It got me thinking about how you can bring some of those features down to C# 2.0 and I came up with the concept of a RichEnumerable. This type can be used for querying using specifications.
The interface implements the IEnumerable interface but extends it with a "Where" method.

    public interface IRichEnumerable< T > : IEnumerable< T >
    {
        IEnumerable< T > Where( ISpecification< T > criteria );
    }

The implementation so far looks like this.

    internal class RichEnumerable< T > : IRichEnumerable< T >
    {
        private readonly IEnumerable< T > _items;

        public RichEnumerable( IEnumerable< T > items )
        {
            _items = items;
        }

        public IEnumerable< T > Where( ISpecification< T > criteria )
        {
            foreach( T item in _items )
            {
                if( criteria.IsSatisfiedBy( item ) )
                {
                    yield return item;
                }
            }
        }

        IEnumerator< T > IEnumerable< T >.GetEnumerator( )
        {
            return _items.GetEnumerator( );
        }

        public IEnumerator GetEnumerator( )
        {
            return ( ( IEnumerable< T > )this ).GetEnumerator( );
        }
    }

This could be extended further to return a RichEnumerable from the where method instead of an IEnumerable so you can filter further.

Just a quick lunch time idea... source is provided.

Programming .NET Components, 2nd Edition by Juval Lowy
Read more about this title...

This was a pretty sweet read, I think this along with CLR via C# work well with one another. This book goes into a little more depth on threading and issues with concurrency. As well the chapters on remoting are long and full of tonnes of information. Way more then this guy could absorb after an initial read. I have so much to learn about remoting.
This book starts right fr gooom the beginning. What is a component?
".. a component is a .NET class. For example, this is a .NET component:

    public class MyClass {
        public string GetMessage() {
            return "Hello";
        }
    }

I think one of my favorite chapters in this book was on "Interface-Based Programming" and talks about the importance of separating interface from implementation.

"Interface Factoring: When you factor an interface, always think in terms of reusable elements. In a component-oriented application, the basic unit of reuse is the interface."

"... proper interface-factoring results in more specialized, loosely coupled, fine-tuned, and reusable interfaces, and subsequently, those benefits apply to the system as well. In general, interface factoring results in interfaces with fewer members."

Another benefit, in my opinion, to interfaces is for learning a system. By checking out the interfaces defined in a subsystem you can get a flavor for what services are offered by each component. It's much easier to look at the interface contract to see the operations it performs then having to scan through concrete types. I equate this to header files in C. If I look at the header file I can see what operations are available from each library. I don't need to know how it was implemented, just where to find it.

"Windows Forms base classes make extensive use of ISynchronizeInvoke. The control class relies on underlying Windows messages and a message-processing loop (the message pump) to process them. The message loop must have thread affinity, because messages to a window are delivered only to the thread that created that window."

Juval shares many different helper classes for getting around some of the more trickier areas of .NET development, like threading, events, remoting and even how to use a mutex to only allow a single instance of a class to run.

    internal static class Program {
        [STAThread]
        private static void Main() {
            if ( IsFirstInstance( ) ) {
                Application.ApplicationExit += OnApplicationExit( );
                Application.Run( new Form1( ) );
            }
        }

        private static bool IsFirstInstance() {
            _mutex = new Mutex( false, Assembly.GetEntryAssembly( ).FullName );
            bool owned = _mutex.WaitOne( TimeSpan.Zero, false );
            return owned;
        }

        private static EventHandler OnApplicationExit() {
            return delegate {
                       _mutex.ReleaseMutex( );
                       _mutex.Close( );
                   };
        }

        private static Mutex _mutex;
    }

I'd like to talk to you for a moment about my man The Event Aggregator. (Homeboy's been tossin' events for years!) Martin Fowler defines the Event Aggregator as:

"Channel events from multiple objects into a single object to simplify registration for clients." - Martin Fowler

But he's so much more then that! This pattern comes in handy in state-ful environments, so.. hello WinForms/WPF. Sorry ASP.NET!

What this guy does is creates a single channel to find out what's going on and to raise events. Through the event aggregator you can subscribe to known events in the system as well as raise known events in the system. Some examples for system wide events are Save, Loading, Shutdown. You can also create concepts for layer specific event aggregators that target certain layers of a system. For example UI only.

 1     public class ApplicationEvents {
 2         private static readonly IEventAggregator aggregator;
 3         public static readonly IEvent Save = new EventRaiser( "Save" );
 4         public static readonly IEvent Loading = new EventRaiser( "Loading" );
 5 
 6         static ApplicationEvents( ) {
 7             aggregator = new EventAggregator( );
 8             aggregator.Register( Save );
 9             aggregator.Register( Loading );
10         }
11 
12         public static void Raise( IEvent eventToRaise ) {
13             aggregator.RaiseEvent( eventToRaise );
14         }
15 
16         public static void SubscribeTo( IEvent eventToSubscribeTo, EventHandler handler ) {
17             aggregator.AddHandler( eventToSubscribeTo.Name, handler );
18         }
19     }

The ApplicationEvents becomes the central point for raising and subscribing to known application wide events. Type can be coupled to the aggregator but not to each other. Let's start with the concept of a named event. An event is really nothing more then a delegate. In .NET there are 2 delegate signatures that are used for all events. The generic and non generic version of the EventHandler delegate. (Read More... ) A named event is an event with a name. He might look something like this guy?

    internal class EventRaiser : IEvent {
        public EventRaiser( string name ) {
            _name = name;
            _handlers = new List< EventHandler >( );
        }

        public string Name {
            get { return _name; }
        }

        public void Add( EventHandler handler ) {
            _handlers.Add( handler );
        }

        public void Raise( ) {
            Raise( null, null );
        }

        public void Raise( object sender, EventArgs data ) {
            foreach ( EventHandler handler in _handlers ) {
                if ( handler != null ) {
                    handler( sender, data );
                }
            }            
        }

        private readonly string _name;
        private readonly IList< EventHandler > _handlers;
    }
    

Underneath the hood it's the aggregator that's maintaining references to all the types that have subscribed to events.

 1     public class EventAggregator : IEventAggregator {
 2         public EventAggregator( ) {
 3             _events = new Dictionary< string, IEvent >( );
 4         }
 5 
 6         public void Register( string eventName ) {
 7             Register( new EventRaiser( eventName ) );
 8         }
 9 
10         public void Register( IEvent eventToAdd ) {
11             EnsureEventHasntBeenRegistered( eventToAdd );
12             _events.Add( eventToAdd.Name, eventToAdd );
13         }
14 
15         public void AddHandler( string eventName, EventHandler handler ) {
16             RetrieveEvent( eventName ).Add( handler );
17         }
18 
19         public void RaiseEvent( string withEventName ) {
20             RaiseEvent< EventArgs >( withEventName, null, EventArgs.Empty );
21         }
22 
23         public void RaiseEvent( IEvent eventToRaise ) {
24             RaiseEvent< EventArgs >( eventToRaise.Name, null, EventArgs.Empty );
25         }
26 
27         public void RaiseEvent< T >( string withEventName, object sender, T data ) where T : EventArgs {
28             RetrieveEvent( withEventName ).Raise( sender, data );
29         }
30 
31         private IEvent RetrieveEvent( string eventName ) {
32             if ( _events.ContainsKey( eventName ) ) {
33                 return _events[ eventName ];
34             }
35             throw new ArgumentNullException( eventName, "The Event Has Not Been Registered." );
36         }
37 
38         private void EnsureEventHasntBeenRegistered( IEvent eventToAdd ) {
39             if ( _events.ContainsKey( eventToAdd.Name ) ) {
40                 throw new ArgumentException( "Event name has already been registered", eventToAdd.Name );
41             }
42         }
43 
44         private readonly IDictionary< string, IEvent > _events;
45     }

The concept is similar to Juval Lowy's EventHelper class defined in...

Programming .NET Components, 2nd Edition by Juval Lowy Read more about this title...

Patterns of Enterprise Application Architecture (The Addison-Wesley Signature Series)
by Martin Fowler

Read more about this title...

This book is amazing, I could probably read it over and over again. The patterns that it presents makes a lot of sense, the actual implementations and examples could probably re-vamped but I'm finding that it's a great starter to trying to understand the concepts.
So today I'm trying to grok this concept of the "IDENTITY MAP". The book defines it as:
"Ensures that each object gets loaded only once by keeping every loaded object in a map. Looks up objects using the map when referring to them."
I put together a quick implementation that I'm using for an assignment I'm writing for school. I'm creating repositories that have 2 dependencies. First dependency is a Data Mapper (not to be confused with a Mapper) and the second is an Identity Map.
As objects are requested from the repository, the repository is checking the identity map to see if an instance has been loaded, if it has it's immediately returned to the caller. If the object is not in the map the repository leverages the data mapper to load the object, then adds it to the map and returns it to the caller.
The Data Mapper is defined as:

"A layer of Mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself." - PoEAA I created a Layer Supertype to register objects in the map. The Domain Layer Super type demands that domain objects had an ID. The ID is what's getting used to load and register objects into the map.
The Layer Supertype is defined as:

"A type that acts as a the supertype for all types in it's layer." - PoEAA

The Domain Layer Super Type.

1     public interface IDomainObject {
2         long ID();
3     }

My actual implementation of the identity map looks like this...

 1     public class IdentityMap> T > : IIdentityMap> T > where T : IDomainObject {
 2         public IdentityMap() {
 3             _items = new List> T >( );
 4         }
 5 
 6         public void Add( T domainObject ) {
 7             EnsureObjectHasNotAlreadyBeenAdded( domainObject );
 8             _items.Add( domainObject );
 9         }
10 
11         public T FindObjectWithIdOf( long idOfObjectToFind ) {
12             foreach ( T item in _items ) {
13                 if ( item.ID( ).Equals( idOfObjectToFind ) ) {
14                     return item;
15                 }
16             }
17             return default( T );
18         }
19 
20         private void EnsureObjectHasNotAlreadyBeenAdded( T domainObject ) {
21             if ( ContainsObjectWithIdOf( domainObject.ID( ) ) ) {
22                 throw new ObjectAlreadyAddedToIdentityMapException( domainObject );
23             }
24         }
25 
26         private readonly IList> T > _items;
27     }

One of the benefits I like about the Identity Map is that it acts as an in memory cache for objects loaded from the database. This reduces the number of trips to and from the persistence store.

Source Code

This month I've been going pretty hard core about learning ASP.NET and I was having a lot of difficulty with playing with the ASPX view engine. I'm already fairly familiar with HTML and CSS, but now I have to learn these new ASP.NET controls? Why can't I just stick to the HTML and CSS I know and enjoy working with?
Well it turns out I can... I don't need to learn about the complex data binding of a GridView or how an ASP:TextBox converts to a plain ol' input tag wrapped in span tags. I've been heavily studying the work from the project we worked on during the Nothin' But .NET boot camp and reading up on the MSDN documentation on inlining aspx.
I like it... C'mon doesn't this....

  <h1>Available Slips</h1>          
  <table>
      <thead>
          <tr>
              <td>Location Name</td>
              <td>Dock Name</td>
              <td>Slip Width</td>
              <td>Slip Length</td>
          </tr>
      </thead>            
  <&#37; foreach ( SlipDisplayDTO item in ViewLuggage.ClaimFor(ViewLuggageTickets.AvailableSlips) )
  {&#37;>
      <tr>
          <td><&#37;= item.LocationName &#37;></td>
          <td>
              <a href='<&#37;= WebViews.DockView.Name( ) &#37;>?<&#37;= PayloadKeys.DockId
                &#37;>=<&#37;= item.DockId &#37;>'>
                  <&#37;= item.DockName &#37;>
              </a>
          </td>
          <td><&#37;= item.Width &#37;></td>
          <td><&#37;= item.Length &#37;></td>        
      </tr>
  <&#37; } &#37;>                    
  </table>

Seem a lot more readable then this...

  <asp:Repeater ID="uxSlipsRepeater" runat="server">
  <HeaderTemplate>
  <table>
  <thead>
      <tr>
          <td>Dock Name</td>
          <td>Slip Width</td>
          <td>Slip Length</td>
      </tr>
  </thead>
  </HeaderTemplate>
  <ItemTemplate>
      <tr>
          <td>
  <a href='DockView.aspx?<&#37;= PayLoadKeys.DockId &#37;>=<&#37;#
    ((SlipDisplayDTO)Container.DataItem).DockId &#37;>'>
  <&#37;# Transform.From(Container.DataItem).AndConvertItToAn<SlipDisplayDTO>().DockName &#37;>
  </a>
          </td>
          <td><&#37;# Transform.From(Container.DataItem).AndConvertItToAn<SlipDisplayDTO>().Width
            &#37;></td>
          <td><&#37;# Transform.From(Container.DataItem).AndConvertItToAn<SlipDisplayDTO>().Length
            &#37;></td>
      </tr>
  </ItemTemplate>
  <FooterTemplate>
  </table>
  </FooterTemplate>
  </asp:Repeater>    

The extra asp namespaces appended to all the controls just seem like noise. The explicit casting from Container.DataItem to the type actually contained seems like extra work. I suppose you could write all this out in an item data bound event handler. But it just looks like noise, noise noise... Then when you actually look at the HTML that's spit out it loaded with more noise...

For example:

  <input 
      name="ctl00$ContentPlaceHolder2$uxUserNameTextBox" 
      type="text" 
      id="ctl00_ContentPlaceHolder2_uxUserNameTextBox" />

Versus:

  <input name="uxUserNameTextBox" type="text" />

Well all of this can be avoided. But you're going to have to get just a little bit deeper, and here's how. Everything you need to know is in HttpContext. Yup!

Instead of dropping an ASP:TextBox on the page try an input element and parse out the value in the input element from the HttpContext.Current.Request.Params. This is a NameValueCollection that has all the Http Headers that were sent along the trip to the server AKA The Payload.

For my current school assignment I'm currently flushing out the concept of an HttpGateway, where all traffic comes in and all traffic goes out. Currently this is just wrapping and HttpContext but with an interface that works better for me as a client of it. I don't need to see everything available in the HttpContext (which is a lot!).

Next up, take advantage of the HttpContext.Items collection. This is a collection of objects which you can load up with extra information to pass on down the pipeline. Consider the concept of view luggage, where luggage is issued a ticket when you drop it off. You can then claim that luggage using the same luggage ticket.

What does this mean, you can have your presenters, controllers, commands (whatever) drop off luggage to be carried to the view. You can then have your views claim that luggage with the luggage ticket. (Take a look back at the first bit of HTML markup in this post.)

The HttpContext.Items collection is a dictionary for objects. Using strongly typed luggage tickets you can make that the key, and the actual luggage the value to store in the items collection. The HttpContext then becomes the airplane, carrier or transporter that hauls your luggage from your presenter, controller, command (whatever) to the view.

For the quick and dirty here's the code that describes what I'm talking about:

    public class ViewLuggageTransporter< Luggage > : IViewLuggageTransporter< Luggage > {
        public ViewLuggageTransporter( IViewLuggageTicket< Luggage > key ) : this( key, HttpContext.Current.Items ) {}

        private ViewLuggageTransporter( IViewLuggageTicket< Luggage > key, IDictionary items ) {
            _ticket = key;
            _items = items;
        }

        public Luggage Value() {
            foreach ( DictionaryEntry entry in _items ) {
                if ( entry.Key.Equals( _ticket ) ) {
                    return ( Luggage )entry.Value;
                }
            }
            return default( Luggage );
        }

        public void Add( Luggage value ) {
            _items.Add( _ticket, value );
        }

        private readonly IViewLuggageTicket< Luggage > _ticket;
        private readonly IDictionary _items;
    }

    public class ViewLuggage {
        public static IViewLuggageTransporter< T > TransporterFor< T >( IViewLuggageTicket< T > ticket ) {
            return new ViewLuggageTransporter< T >( ticket );
        }

        public static T ClaimFor< T >( IViewLuggageTicket< T > ticket ) {
            return new ViewLuggageTransporter< T >( ticket ).Value( );
        }
    }

To parse out the value submitted in a request you can create mappers to parse out the values for each control. In the code below each of the string literals prefixed with a "ux" represents the name of the html control that was on the page.

    public class UpdateRegistrationPresentationMapper : IUpdateRegistrationPresentationMapper {
        public UpdateCustomerRegistrationDTO MapFrom( IHttpRequest input ) {
            return new UpdateCustomerRegistrationDTO(
                input.ParsePayloadFor( PayloadKeys.CustomerId ),
                input.ParsePayloadFor( PayloadKeys.For( "uxUserNameTextBox" ) ),
                input.ParsePayloadFor( PayloadKeys.For( "uxPasswordTextBox" ) ),
                input.ParsePayloadFor( PayloadKeys.For( "uxFirstNameTextBox" ) ),
                input.ParsePayloadFor( PayloadKeys.For( "uxLastNameTextBox" ) ),
                input.ParsePayloadFor( PayloadKeys.For( "uxPhoneNumberTextBox" ) ),
                input.ParsePayloadFor( PayloadKeys.For( "uxCityTextBox" ) )
                );
        }
    }

Next up, figuring out a cleaner way to implement authorization and authentication without having to rely on the FormsAuthentication class. So far my spiking of Forms Auth looks something like the code below... *Please do not use the code below. I was just trying to understand how forms auth works and this is not a great example of how you should use it.

        public void AuthenticateHttpRequest( ) {
            HttpCookie cookie = GetCookieFrom( HttpContext.Current );
            if ( null != cookie ) {
                BindPrincipalToThreadUsing( _mapper.MapFrom( FormsAuthentication.Decrypt( cookie.Value ) ) );
            }
        }

        private HttpCookie GetCookieFrom( HttpContext context ) {
            return context.Request.Cookies[ FormsAuthentication.FormsCookieName ];
        }

        private void BindPrincipalToThreadUsing( CustomerCookieCredentials credentials ) {
            IIdentity identity = new CustomerIdentity( credentials.Username, credentials.Username );
            HttpContext.Current.User = new GenericPrincipal( identity, new string[] {"customer"} );
        }

        private void AddAuthenticationTicket( ) {
            FormsAuthenticationTicket ticket =
                new FormsAuthenticationTicket( 1, "mo", DateTime.Now, DateTime.Now.AddMinutes( 20 ), false, "2" );
            string cookieValue = FormsAuthentication.Encrypt( ticket );
            HttpContext current = HttpContext.Current;
            current.Response.Cookies.Add( new HttpCookie( FormsAuthentication.FormsCookieName, cookieValue ) );

            IIdentity identity = new CustomerIdentity( "mo", "2" );
            current.User = new GenericPrincipal( identity, new string[] {"customer"} );
        }

One of the benefits about building with NAnt is being able to flip the switch and start targeting a different compiler, without having to switch to the latest version of Visual Studio. Although, you wont get the intellisense provided by studio for new features.
So today we flipped the switch on a project at work, from targeting the C# 2.0 compiler to the C# 3.0 compiler. We haven't started leveraging any of the new functionality available in the new compiler but at least we know we can start.
So to flip the switch you'll need to update your "nant.exe.config" file to include the .NET Framework version 3.5. Remember with this release we got a new version of the .NET Framework assemblies, a new C# 3.0 compiler but we're still running it all in the 2.0 version of the CLR.
The new xml element to add to your "Nant.exe.config" file looks something like this:

  <framework
      name="net-3.5"
      family="net"
      version="3.5"
      description="Microsoft .NET Framework 3.5"
      runtimeengine=""
      sdkdirectory="${path::combine(sdkInstallRoot, 'bin')}"
      frameworkdirectory="${path::combine(installRoot, 'v3.5')}"
      frameworkassemblydirectory="${path::combine(installRoot, 'v2.0.50727')}"
      clrversion="2.0.50727">
      <task-assemblies>
          <!-- include .NET specific assemblies -->
          <include name="tasks/net/*.dll" />
          <!-- include .NET 2.0 specific assemblies -->
          <include name="tasks/net/2.0/**/*.dll" />
          <!-- include Microsoft.NET specific task assembly -->
          <include name="NAnt.MSNetTasks.dll" />
          <!-- include Microsoft.NET specific test assembly -->
          <include name="NAnt.MSNet.Tests.dll" />
      </task-assemblies>
      <project>
          <readregistry
              property="installRoot"
              key="SOFTWARE\Microsoft\.NETFramework\InstallRoot"
              hive="LocalMachine" />
          <readregistry
              property="sdkInstallRoot"
              key="SOFTWARE\Microsoft\.NETFramework\sdkInstallRootv2.0"
              hive="LocalMachine"
              failonerror="false" />
      </project>
      <tasks>
          <task name="csc">
              <attribute name="exename">csc</attribute>
              <attribute name="supportsnowarnlist">true</attribute>
              <attribute name="supportswarnaserrorlist">true</attribute>
              <attribute name="supportskeycontainer">true</attribute>
              <attribute name="supportskeyfile">true</attribute>
              <attribute name="supportsplatform">true</attribute>
              <attribute name="supportslangversion">true</attribute>
          </task>
          <task name="vbc">
              <attribute name="exename">vbc</attribute>
              <attribute name="supportsdocgeneration">true</attribute>
              <attribute name="supportsnostdlib">true</attribute>
              <attribute name="supportsnowarnlist">true</attribute>
              <attribute name="supportskeycontainer">true</attribute>
              <attribute name="supportskeyfile">true</attribute>
              <attribute name="supportsplatform">true</attribute>
              <attribute name="supportswarnaserrorlist">true</attribute>
          </task>
          <task name="jsc">
              <attribute name="exename">jsc</attribute>
              <attribute name="supportsplatform">true</attribute>
          </task>
          <task name="vjc">
              <attribute name="exename">vjc</attribute>
              <attribute name="supportsnowarnlist">true</attribute>
              <attribute name="supportskeycontainer">true</attribute>
              <attribute name="supportskeyfile">true</attribute>
          </task>
          <task name="resgen">
              <attribute name="exename">resgen</attribute>
              <attribute name="supportsassemblyreferences">true</attribute>
              <attribute name="supportsexternalfilereferences">true</attribute>
          </task>
          <task name="al">
              <attribute name="exename">al</attribute>
          </task>
          <task name="delay-sign">
              <attribute name="exename">sn</attribute>
          </task>
          <task name="license">
              <attribute name="exename">lc</attribute>
              <attribute name="supportsassemblyreferences">true</attribute>
          </task>
          <task name="ilasm">
              <attribute name="exename">ilasm</attribute>
          </task>
          <task name="ildasm">
              <attribute name="exename">ildasm</attribute>
          </task>
      </tasks>
  </framework>                 

To flip the switch you can either override the nant setting in your build file ...

  <property name="nant.settings.currentframework" value="net-3.5" />

or you can change the default target framework in the "nant.exe.config" file.

  <platform name="win32" default="net-3.5">

Source Nant.exe.config

Archive