<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Andy Pike</title>
	<atom:link href="http://andypike.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://andypike.wordpress.com</link>
	<description>My personal blog about all sorts of random stuff</description>
	<lastBuildDate>Mon, 08 Mar 2010 21:36:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='andypike.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Andy Pike</title>
		<link>http://andypike.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://andypike.wordpress.com/osd.xml" title="Andy Pike" />
	<atom:link rel='hub' href='http://andypike.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Castlecasts.com is live!</title>
		<link>http://andypike.wordpress.com/2010/03/08/castlecasts-com-is-live/</link>
		<comments>http://andypike.wordpress.com/2010/03/08/castlecasts-com-is-live/#comments</comments>
		<pubDate>Mon, 08 Mar 2010 21:36:27 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[Castle]]></category>
		<category><![CDATA[Castlecasts]]></category>

		<guid isPermaLink="false">http://andypike.wordpress.com/?p=72</guid>
		<description><![CDATA[After a few evenings hard work, I can now announce that castlecasts.com is now live! Currently there is only one screencast to watch but I&#8217;ll be building on this in the coming weeks. If you have any ideas for future episodes or feedback for the site feel free to post them on the forum. I&#8217;ll [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=72&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>After a few evenings hard work, I can now announce that <a href="http://castlecasts.com" target="_blank">castlecasts.com</a> is now live!</p>
<p>Currently there is only one screencast to watch but I&#8217;ll be building on this in the coming weeks. If you have any ideas for future episodes or feedback for the site feel free to <a href="http://castlecasts.uservoice.com" target="_blank">post them on the forum</a>.</p>
<p>I&#8217;ll be adding a submission form soon so you can submit your own screencasts for inclusion in the site. If you want to submit a Castlecast before this is ready, just email me the details at: andy[at]castlecasts.com.</p>
<p>Now a big thank you to the Castle team, especially Henry Conceição for space on the <a href="http://builds.castleproject.org" target="_blank">Castle build server</a> and also for the hosting of the site. You guys rock!</p>
<p>If you&#8217;re interested in how the site was built then the source is available on <a href="http://github.com/andypike/Castlecasts/tree/master/Website/" target="_blank">GitHub</a> so feel free to take a look and if you fancy sending me a pull request, I&#8217;d be happy to receive them ;o)</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andypike.wordpress.com/72/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andypike.wordpress.com/72/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andypike.wordpress.com/72/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andypike.wordpress.com/72/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andypike.wordpress.com/72/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andypike.wordpress.com/72/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andypike.wordpress.com/72/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andypike.wordpress.com/72/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andypike.wordpress.com/72/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andypike.wordpress.com/72/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andypike.wordpress.com/72/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andypike.wordpress.com/72/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andypike.wordpress.com/72/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andypike.wordpress.com/72/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=72&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andypike.wordpress.com/2010/03/08/castlecasts-com-is-live/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/196ab25f16dcfd37518a41ceb15e0da0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">andypike</media:title>
		</media:content>
	</item>
		<item>
		<title>Introducing Castlecasts</title>
		<link>http://andypike.wordpress.com/2010/02/28/introducing-castlecasts/</link>
		<comments>http://andypike.wordpress.com/2010/02/28/introducing-castlecasts/#comments</comments>
		<pubDate>Sun, 28 Feb 2010 18:17:22 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[Castle]]></category>
		<category><![CDATA[Castlecasts]]></category>

		<guid isPermaLink="false">http://andypike.wordpress.com/?p=65</guid>
		<description><![CDATA[It&#8217;s been a very long time since I lasted blogged but I&#8217;ve found some time and would like to take this opportunity to announce Castlecasts. After doing a lot of learning in Ruby on Rails, one of the best resources that I found was the www.railscasts.com site. For those who don&#8217;t know, it contains over [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=65&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s been a very long time since I lasted blogged but I&#8217;ve found some time and would like to take this opportunity to announce <strong>Castlecasts</strong>.</p>
<p>After doing a lot of learning in Ruby on Rails, one of the best resources that I found was the <a href="http://www.railscasts.com" target="_blank">www.railscasts.com</a> site. For those who don&#8217;t know, it contains over 200 screencasts about various aspects of programming in RoR. So I posted the idea of creating a similar site for the CastleProject which seemed to have some interest.</p>
<p>I found some spare time and have decided to start castlecasts.com. I&#8217;ve been looking for a way to give back to the Castle team for a while as I&#8217;ve been using their components for over 2 years. I think this could be an excellent resource for the Castle community, if you have any questions or comments please let me know.</p>
<p>The site isn&#8217;t ready yet but I have created the first screencast. It&#8217;s hosted on <a href="http://www.vimeo.com" target="_blank">Vimeo</a> (for now) to keep hosting costs down. Once the site is ready I&#8217;ll let you know, but in the meantime, here is the first episode:</p>
<p><a href="http://vimeo.com/9802683">Getting Started With MonoRail</a> from <a href="http://vimeo.com/user3270191">Andy Pike</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
<p>You can get the source code for this episode on github: <a href="http://github.com/andypike/Castlecasts" target="_blank">http://github.com/andypike/Castlecasts</a></p>
<p>I plan on adding a whole bunch more episodes, so if you have a suggestion for something to cover or have a screencast you would like to add, DM me on twitter: <a href="http://twitter.com/andypike">@andypike</a></p>
<p>I&#8217;ll be on the look out for some hosting, so if you feel like sponsoring castlecasts.com, donation of hosting would be cool ;o) I&#8217;m working on the site now, should have something simple up and running soon. Then I&#8217;ll start creating more episodes.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andypike.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andypike.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andypike.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andypike.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andypike.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andypike.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andypike.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andypike.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andypike.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andypike.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andypike.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andypike.wordpress.com/65/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andypike.wordpress.com/65/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andypike.wordpress.com/65/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=65&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andypike.wordpress.com/2010/02/28/introducing-castlecasts/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/196ab25f16dcfd37518a41ceb15e0da0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">andypike</media:title>
		</media:content>
	</item>
		<item>
		<title>Building .NET Solution with Rake and TeamCity</title>
		<link>http://andypike.wordpress.com/2009/08/08/building-net-solution-with-rake-and-teamcity/</link>
		<comments>http://andypike.wordpress.com/2009/08/08/building-net-solution-with-rake-and-teamcity/#comments</comments>
		<pubDate>Sat, 08 Aug 2009 22:33:41 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Rake]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[TeamCity]]></category>

		<guid isPermaLink="false">http://andypike.wordpress.com/?p=56</guid>
		<description><![CDATA[I&#8217;ve been reading through my Ruby books and came across Rake. Rake is a Ruby build program similar to NAnt or MSBuild but instead of writing XML, you use Ruby instead. Now that opens all sorts of doors, so I thought I&#8217;d see if I could get Rake to build a .NET solution and take [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=56&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been reading through my Ruby books and came across Rake. Rake is a Ruby build program similar to NAnt or MSBuild but instead of writing XML, you use Ruby instead. Now that opens all sorts of doors, so I thought I&#8217;d see if I could get Rake to build a .NET solution and take it from there.</p>
<p>First things first, if you want to do this you will need to <a href="http://www.ruby-lang.org/en/downloads/" target="_blank">download and install Ruby</a>, luckily for us, Rake is included. You will need to reboot after to ensure your PATH is updated.</p>
<p>Now we are ready to rumble. First thing I wanted to try was just compiling a solution – nice and simple. There were a few samples around the interweb, and I soon created the following:</p>
<div style="color:black;border-left:1px solid gray;border-bottom:1px solid gray;line-height:12pt;background-color:#f4f4f4;width:97.5%;">
<div style="line-height:12pt;background-color:#f4f4f4;width:100%;">
<pre style="line-height:12pt;background-color:white;width:100%;">DOT_NET_PATH = <span style="color:#006080;">"#{ENV["</span>SystemRoot<span style="color:#006080;">"]}\\Microsoft.NET\\Framework\\v3.5"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">SOURCE_PATH = <span style="color:#006080;">"../src"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">CONFIG = <span style="color:#006080;">"Release"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">task :<span style="color:#0000ff;">default</span> =&gt; [<span style="color:#006080;">"build:all"</span>]</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;"><span style="color:#0000ff;">namespace</span> :build <span style="color:#0000ff;">do</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    task :all =&gt; [:compile]</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    desc <span style="color:#006080;">"Build solution using MSBuild."</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    task :compile <span style="color:#0000ff;">do</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        puts <span style="color:#006080;">"Compiling Solution..."</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        solutions = FileList[<span style="color:#006080;">"#{SOURCE_PATH}/**/*.sln"</span>]</pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        solutions.each <span style="color:#0000ff;">do</span> |solution|</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">          sh <span style="color:#006080;">"#{DOT_NET_PATH}/msbuild.exe /p:Configuration=#{CONFIG} #{solution} /t:Rebuild"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        end</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    end</pre>
<pre style="line-height:12pt;background-color:white;width:100%;"></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">end</pre>
</div>
</div>
<p>Save this file as <strong>“rakefile.rb”</strong> and put it in a folder called <strong>“build”</strong> which is at the same level as the <strong>“src”</strong> folder. Then at a command prompt, navigate to the build folder and use the following command:</p>
<pre>C:\MyRakeSample\build&gt;rake</pre>
<p>It worked!</p>
<p>Inside the Rake file we define the default build task as the <strong>:all </strong>task that is inside our <strong>build</strong> namespace. This task currently consists of one task <strong>:compile. </strong>The <strong>:compile</strong> task searches the <strong>src</strong> folder for any solution files and the builds them using MSBuild in release.</p>
<p>That was pretty easy and worked without a hitch. So next, I wanted to list the things I wanted my new build script to do:</p>
<ol>
<li>Get the current SVN revision number</li>
<li>Update all AssemblyInfo.cs files with a new version number that contains this SVN rev number</li>
<li>Build the solution (as above)</li>
<li>Run NUnit tests</li>
<li>Create test coverage report</li>
<li>Copy all the files that need to be deployed (excluding those that don’t)</li>
<li>Zip up these files into a deployment package</li>
<li>Integrate as much as possible with TeamCity</li>
<li>Should be able to run the same build script locally as well as with TeamCity</li>
</ol>
<p>It took a little but I got it working. <a href="http://aardvark-cms.googlecode.com/svn/trunk/build/rakefile.rb" target="_blank">You can see the full file here</a>. Below is a breakdown of each section:</p>
<h4></h4>
<h3>Getting the current SVN revision number</h3>
<p>First off, you’ll need to get the <a href="http://www.collab.net/downloads/subversion/" target="_blank">SVN command line client downloaded and installed</a>. You will need to reboot after to ensure your PATH is updated.</p>
<p>I decided to add a new :init task that should clean up, create folders and get the SVN HEAD revision number. So here is the new code I’ve added:</p>
<div style="color:black;border-left:1px solid gray;border-bottom:1px solid gray;line-height:12pt;background-color:#f4f4f4;width:97.5%;">
<div style="line-height:12pt;background-color:#f4f4f4;width:100%;">
<pre style="line-height:12pt;background-color:white;width:100%;">require <span style="color:#006080;">'rexml/document'</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">....</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">OUTPUT_PATH = <span style="color:#006080;">"output"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">SVN_LOG_PATH = <span style="color:#006080;">"#{OUTPUT_PATH}/svn_log.xml"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">ARTIFACTS_PATH = <span style="color:#006080;">"#{OUTPUT_PATH}/artifacts"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">SVN_URL = <span style="color:#006080;">"http://aardvark-cms.googlecode.com/svn/trunk/"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">VERSION_MAJOR_MINOR_BUILD = <span style="color:#006080;">"0.1.0"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;"><span style="color:#0000ff;">namespace</span> :build <span style="color:#0000ff;">do</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    task :all =&gt; [:init, :compile]</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    ....</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    desc <span style="color:#006080;">"Perform the required initial tasks."</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    task :init <span style="color:#0000ff;">do</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        puts <span style="color:#006080;">"Performing Initialization..."</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        puts <span style="color:#006080;">"Creating folders..."</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        Dir.mkdir(OUTPUT_PATH)</pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        Dir.mkdir(ARTIFACTS_PATH)</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        puts <span style="color:#006080;">"Getting SVN revision number and saving to #{SVN_LOG_PATH}..."</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        sh <span style="color:#006080;">"svn log --xml --revision HEAD #{SVN_URL} &gt; \"#{SVN_LOG_PATH}\""</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        log = REXML::Document.<span style="color:#0000ff;">new</span> File.<span style="color:#0000ff;">new</span>(SVN_LOG_PATH)</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        logEntry = log.root.elements[<span style="color:#006080;">"logentry"</span>]</pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        $svn_revision = logEntry.attributes[<span style="color:#006080;">"revision"</span>]</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        $svn_message = logEntry.elements[<span style="color:#006080;">"msg"</span>].text</pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        VERSION = <span style="color:#006080;">"#{VERSION_MAJOR_MINOR_BUILD}.#{$svn_revision}"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        puts <span style="color:#006080;">"Revision #{$svn_revision} found with message: #{$svn_message}"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    end</pre>
<pre style="line-height:12pt;background-color:white;width:100%;">end</pre>
</div>
</div>
<p>There are a bunch of new constants and I’ve included the an xml parser at the top. Then I’ve added a new task called <strong>:init</strong> and added it to the <strong>:all</strong> task before the <strong>:compile</strong> task.</p>
<p>Inside the <strong>:init</strong> task we create some folders, then we use the SVN command line tool to request the HEAD revision information from the repository url and save it as xml to the output folder that is inside our build folder.</p>
<p>Once there, we can read the details from this xml file and create a version number for our application.</p>
<h3>Updating AssemblyInfo.cs with new version number</h3>
<p>Now that we have the SVN revision number and have generated a version number for the current build we need to apply it to our assemblies. We do that by rewriting the AssemblyInfo.cs file for each assembly in our solution. That calls for a new task:</p>
<div style="color:black;border-left:1px solid gray;border-bottom:1px solid gray;line-height:12pt;background-color:#f4f4f4;width:97.5%;">
<div style="line-height:12pt;background-color:#f4f4f4;width:100%;">
<pre style="line-height:12pt;background-color:white;width:100%;">PROJECT_NAME = <span style="color:#006080;">"Aardvark"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">COPYRIGHT = <span style="color:#006080;">"Copyright 2009 1minus1 Ltd. All rights reserved."</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;"></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"><span style="color:#0000ff;">namespace</span> :build <span style="color:#0000ff;">do</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;"></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    task :all =&gt; [:init, :writeAssemblyInfo, :compile]</pre>
<pre style="line-height:12pt;background-color:white;width:100%;"></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    ....</pre>
<pre style="line-height:12pt;background-color:white;width:100%;"></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    desc <span style="color:#006080;">"Write AssemblyInfo.cs with current svn revision."</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    task :writeAssemblyInfo =&gt; [:init] <span style="color:#0000ff;">do</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    puts <span style="color:#006080;">"Writing AssemblyInfo Files..."</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;"></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        assemblyInfoFiles = FileList[<span style="color:#006080;">"#{SOURCE_PATH}/**/AssemblyInfo.cs"</span>]</pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        assemblyInfoFiles.each <span style="color:#0000ff;">do</span> |filePath|</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">            puts <span style="color:#006080;">"AssemblyInfo file found at: #{filePath}"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">            file = File.<span style="color:#0000ff;">new</span>(filePath, <span style="color:#006080;">"w"</span>)</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">            file.puts <span style="color:#006080;">"//This file was generated by the rakefile.rb build script"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">            file.puts <span style="color:#006080;">"using System.Reflection;"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">            file.puts <span style="color:#006080;">"using System.Runtime.InteropServices;\r\n"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">            file.puts <span style="color:#006080;">"[assembly: AssemblyTitle(\"#{PROJECT_NAME} for .NET 3.5\")]"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">            file.puts <span style="color:#006080;">"[assembly: AssemblyDescription(\"\")]"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">            file.puts <span style="color:#006080;">"[assembly: AssemblyConfiguration(\"\")]"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">            file.puts <span style="color:#006080;">"[assembly: AssemblyCompany(\"\")]"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">            file.puts <span style="color:#006080;">"[assembly: AssemblyProduct(\"#{PROJECT_NAME}\")]"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">            file.puts <span style="color:#006080;">"[assembly: AssemblyCopyright(\"#{COPYRIGHT}\")]"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">            file.puts <span style="color:#006080;">"[assembly: AssemblyTrademark(\"\")]"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">            file.puts <span style="color:#006080;">"[assembly: AssemblyCulture(\"\")]"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">            file.puts <span style="color:#006080;">"[assembly: ComVisible(false)]"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">            file.puts <span style="color:#006080;">"[assembly: AssemblyVersion(\"#{VERSION}\")]"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">            file.puts <span style="color:#006080;">"[assembly: AssemblyFileVersion(\"#{VERSION}\")]"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">            file.close</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        end</pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    end</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">end</pre>
</div>
</div>
<p>This is pretty straightforward, we search for all the AssemblyInfo.cs files and then loop through them overwriting them as we go with a new set of attributes. We’ve defined a couple of new constants at the top to use, but the important thing is the use of the newly generated version number.</p>
<p>We add this new <strong>:writeAssemblyInfo</strong> task to the <strong>:all</strong> build task before we compile to ensure that every build will include the correct revision number.</p>
<h3>Run NUnit Tests</h3>
<p>Now we have built our solution, we need to run the tests. Here we need to do something a bit extra as we want to use the TeamCity NUint runner if it is TeamCity running the build. Otherwise we want to use the normal NUnit console for when we are running the build locally.</p>
<div style="color:black;border-left:1px solid gray;border-bottom:1px solid gray;line-height:12pt;background-color:#f4f4f4;width:97.5%;">
<div style="line-height:12pt;background-color:#f4f4f4;width:100%;">
<pre style="line-height:12pt;background-color:white;width:100%;">TEAMCITY_NUNIT_RUNNER = ENV[<span style="color:#006080;">"teamcity.dotnet.nunitlauncher"</span>]</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">NUNIT_EXE = <span style="color:#006080;">"../tools/NUnit/nunit-console.exe"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;"></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"><span style="color:#0000ff;">namespace</span> :build <span style="color:#0000ff;">do</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;"></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    task :all =&gt; [:init, :writeAssemblyInfo, :compile, :test]</pre>
<pre style="line-height:12pt;background-color:white;width:100%;"></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    ...</pre>
<pre style="line-height:12pt;background-color:white;width:100%;"></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    desc <span style="color:#006080;">"Runs tests with NUnit only (without coverage)."</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    task :test =&gt; [:compile] <span style="color:#0000ff;">do</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        puts <span style="color:#006080;">"Running Tests..."</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        tests = FileList[<span style="color:#006080;">"#{SOURCE_PATH}/**/#{CONFIG}/*.Tests.dll"</span>].exclude(/obj\<span style="color:#008000;">//)</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        #Select the correct test runner</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        <span style="color:#0000ff;">if</span>(TEAMCITY_NUNIT_RUNNER == nil)</pre>
<pre style="line-height:12pt;background-color:white;width:100%;">            sh <span style="color:#006080;">"#{NUNIT_EXE} #{tests} /nologo /exclude:Acceptance /xml=#{OUTPUT_PATH}/TestResults.xml"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        <span style="color:#0000ff;">else</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">            sh <span style="color:#006080;">"#{TEAMCITY_NUNIT_RUNNER} v2.0 x86 NUnit-2.4.6 /category-exclude:Acceptance #{tests}"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        end</pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    end</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">end</pre>
</div>
</div>
<p>In this task we first get a list of all the test assemblies based on our naming convention (they end in .Tests.dll) and make sure we exclude any from the obj folders. Then if the TeamCity NUnit runner environment variable is available we use that to run the tests, otherwise, use the NUnit console program that we store in a <strong>tools</strong> folder. At present we are excluding out WatiN acceptance tests, but more on this later.</p>
<p>Using the TeamCity NUnit runner is important to us as it will ensure that the TeamCity test UI and data are updated correctly.</p>
<h3>Create test coverage report</h3>
<p>This is where it gets interesting for me. Adding test coverage reports is a good way to ensure that you (or someone else) hasn’t been lazy and written some code without a test first. I don’t think that you should have a fixed percentage that must be covered, be pragmatic.</p>
<div style="color:black;border-left:1px solid gray;border-bottom:1px solid gray;line-height:12pt;background-color:#f4f4f4;width:97.5%;">
<div style="line-height:12pt;background-color:#f4f4f4;width:100%;">
<pre style="line-height:12pt;background-color:white;width:100%;">NCOVER_EXE = <span style="color:#006080;">"../tools/NCover/NCover.Console.exe"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">NCOVER_EXPLORER_EXE = <span style="color:#006080;">"../tools/NCoverExplorer/NCoverExplorer.Console.exe"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">COVERAGE_ASSEMBLIES = <span style="color:#006080;">"OneMinusOne.Aardvark.Web;OneMinusOne.Aardvark.Framework;OneMinusOne.Aardvark.Entities;OneMinusOne.Aardvark.Core"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">task :<span style="color:#0000ff;">default</span> =&gt; [<span style="color:#006080;">"build:all"</span>]</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;"><span style="color:#0000ff;">namespace</span> :build <span style="color:#0000ff;">do</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    task :all =&gt; [:init, :writeAssemblyInfo, :compile, :test, :coverage]</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    ...</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    desc <span style="color:#006080;">"Run tests with NUnit and NCover for coverage. NCoverExplorer is used to format the coverage results into html."</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    task :coverage =&gt; [:compile] <span style="color:#0000ff;">do</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        puts <span style="color:#006080;">"Running Tests with Coverage..."</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        tests = FileList[<span style="color:#006080;">"#{SOURCE_PATH}/**/#{CONFIG}/*.Tests.dll"</span>].exclude(/obj\<span style="color:#008000;">//)</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        sh <span style="color:#006080;">"#{NCOVER_EXE} #{NUNIT_EXE} #{tests} /nologo /exclude:Acceptance /xml=#{OUTPUT_PATH}/TestResults.xml //reg //x #{OUTPUT_PATH}/Coverage.xml //l #{OUTPUT_PATH}/Coverage.log //ea System.CodeDom.Compiler.GeneratedCodeAttribute //a #{COVERAGE_ASSEMBLIES}"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        sh <span style="color:#006080;">"#{NCOVER_EXPLORER_EXE} #{OUTPUT_PATH}/Coverage.xml /r:ModuleClassFunctionSummary /p:#{PROJECT_NAME} /q /h /so:2 /m:80 /h:#{OUTPUT_PATH}/CoverageReport.html"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    end</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">end</pre>
</div>
</div>
<p>This is a pretty short task. First we use NCover to profile the code while it’s tests are run, then we use NCover Explorer to generate a nice html report. We’ve stored these two programs in our tools folder so you don’t need them installed and it’s easier to get the build running.</p>
<p>You need to do a few extra things in TeamCity to get this to work and show up on a new tab. Here’s what you need to do:</p>
<ol>
<li>Ensure that the build agent service is logged in as an administrator. Otherwise NCover will not be able to profile the tests and you’ll see the error “Profiler connection not established” in your build log.</li>
<li>Add the html report that NCover Explorer generates to your TeamCity artifacts under a folder called Reports.</li>
<li>Edit the TeamCity main-config.xml file <a href="http://www.jetbrains.net/confluence/display/TCD3/Including+Third-Party+Reports+in+the+Build+Results" target="_blank">as shown here</a> to add a tab for your html report.</li>
</ol>
<h3>Create a deployment package</h3>
<p>The last thing that I want my Rake build to do is to collect together the files I need to deploy and zip them up for me.</p>
<div style="color:black;border-left:1px solid gray;border-bottom:1px solid gray;line-height:12pt;background-color:#f4f4f4;width:97.5%;">
<div style="line-height:12pt;background-color:#f4f4f4;width:100%;">
<pre style="line-height:12pt;background-color:white;width:100%;">ARTIFACTS_PATH = <span style="color:#006080;">"#{OUTPUT_PATH}/artifacts"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">WEB_PROJECT_PATH = <span style="color:#006080;">"../src/OneMinusOne.Aardvark.Web"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">ZIP_EXE = <span style="color:#006080;">"../tools/7Zip/7za.exe"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">task :<span style="color:#0000ff;">default</span> =&gt; [<span style="color:#006080;">"build:all"</span>]</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;"><span style="color:#0000ff;">namespace</span> :build <span style="color:#0000ff;">do</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    task :all =&gt; [:init, :writeAssemblyInfo, :compile, :test, :coverage, :package]</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    ...</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    desc <span style="color:#006080;">"Package the required artifacts."</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    task :package =&gt; [:compile] <span style="color:#0000ff;">do</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        puts <span style="color:#006080;">"Preparing package files..."</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        Dir.mkdir <span style="color:#006080;">"#{ARTIFACTS_PATH}/bin"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        FileUtils.cp_r FileList[<span style="color:#006080;">"#{WEB_PROJECT_PATH}/bin/*.dll"</span>], <span style="color:#006080;">"#{ARTIFACTS_PATH}/bin"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        FileUtils.cp_r <span style="color:#006080;">"#{WEB_PROJECT_PATH}/Content"</span>, <span style="color:#006080;">"#{ARTIFACTS_PATH}"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        FileUtils.cp_r <span style="color:#006080;">"#{WEB_PROJECT_PATH}/Views"</span>, <span style="color:#006080;">"#{ARTIFACTS_PATH}"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        FileUtils.cp_r FileList[<span style="color:#006080;">"#{WEB_PROJECT_PATH}/*.aspx"</span>], <span style="color:#006080;">"#{ARTIFACTS_PATH}"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        FileUtils.cp_r FileList[<span style="color:#006080;">"#{WEB_PROJECT_PATH}/*.asax"</span>], <span style="color:#006080;">"#{ARTIFACTS_PATH}"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        FileUtils.cp_r FileList[<span style="color:#006080;">"#{WEB_PROJECT_PATH}/*.config"</span>], <span style="color:#006080;">"#{ARTIFACTS_PATH}"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;"></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        delete_svn_folders(ARTIFACTS_PATH)</pre>
<pre style="line-height:12pt;background-color:white;width:100%;"></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        puts <span style="color:#006080;">"Creating zip package"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;"></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        zipFolder(ARTIFACTS_PATH, <span style="color:#006080;">"#{OUTPUT_PATH}/#{PROJECT_NAME}-v#{VERSION}.zip"</span>);</pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    end</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;"></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">    def delete_svn_folders(folder)</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">        Find.find(folder) <span style="color:#0000ff;">do</span> |path|</pre>
<pre style="line-height:12pt;background-color:white;width:100%;">            <span style="color:#0000ff;">if</span>(path =~ /\.svn$/ || path =~ /\_svn$/)</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">                puts <span style="color:#006080;">"Deleting: #{path}"</span></pre>
<pre style="line-height:12pt;background-color:white;width:100%;">                FileUtils.rm_r path, :force =&gt; <span style="color:#0000ff;">true</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">            end</pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        end</pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    end</pre>
<pre style="line-height:12pt;background-color:white;width:100%;"></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    def zipFolder(folderPath, zipPath)</pre>
<pre style="line-height:12pt;background-color:white;width:100%;">        sh <span style="color:#006080;">"#{ZIP_EXE} a #{zipPath} .\\#{folderPath}\\*"</span></pre>
<pre style="line-height:12pt;background-color:#f4f4f4;width:100%;">    end</pre>
<pre style="line-height:12pt;background-color:white;width:100%;">end</pre>
</div>
</div>
<p>As this is a <a href="http://www.castleproject.org" target="_blank">Castle MonoRail</a> application, I start this new <strong>:package</strong> task by copying all the required web files to an <strong>artifacts</strong> folder that is inside the <strong>output</strong> folder we created earlier. This ensures that we only have the files required to run the application and we exclude all other files.</p>
<p>Once the files are copied I noticed that because we were copying folders, the hidden .svn folders were being copied too. The only way I could see was to then delete these folders from the artifacts folder. This is where the <strong>delete_svn_folders</strong> function comes in. It just loops through and deletes any path that ends with either .svn or _svn as either can be used.</p>
<p>The final thing is to zip these files up. I use the <a href="http://www.7-zip.org/download.html" target="_blank">7zip command line tool</a> to do this and I’ve added this to the tools folder again to make it as easy as possible to run the build. The zip file is saved to the output folder and is named with the project name and version number.</p>
<h3>Finishing up</h3>
<p>That’s it really, you can see the <a href="http://aardvark-cms.googlecode.com/svn/trunk/build/rakefile.rb" target="_blank">full build file here at Google Code</a>. There are some extra bits and pieces in this build like coping the files to the development server, requesting an installer page on the site that will install the database and populate it with data but that was a bit specific for our needs so I didn’t add it here.</p>
<p>The advantage I can see here using Rake over NAnt or MSBuild is that you can program your build <em>using code</em> rather than xml which I find a lot easier and a lot more powerful.</p>
<p>The one thing that is missing from the build is the ability to run our acceptance tests that are written using <a href="http://watin.sourceforge.net/" target="_blank">WatiN</a>. I found <a href="http://stackoverflow.com/questions/488443/running-watin-on-teamcity" target="_blank">this post on Stack Overflow</a> and <a href="http://www.jetbrains.net/devnet/message/5242725" target="_blank">this post on JetBrains forum</a> which may point me in the right direction.</p>
<p>I hope that has helped, Rake is the future…</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andypike.wordpress.com/56/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andypike.wordpress.com/56/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andypike.wordpress.com/56/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andypike.wordpress.com/56/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andypike.wordpress.com/56/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andypike.wordpress.com/56/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andypike.wordpress.com/56/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andypike.wordpress.com/56/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andypike.wordpress.com/56/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andypike.wordpress.com/56/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andypike.wordpress.com/56/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andypike.wordpress.com/56/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andypike.wordpress.com/56/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andypike.wordpress.com/56/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=56&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andypike.wordpress.com/2009/08/08/building-net-solution-with-rake-and-teamcity/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/196ab25f16dcfd37518a41ceb15e0da0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">andypike</media:title>
		</media:content>
	</item>
		<item>
		<title>Learning Ruby</title>
		<link>http://andypike.wordpress.com/2009/07/17/learning-ruby/</link>
		<comments>http://andypike.wordpress.com/2009/07/17/learning-ruby/#comments</comments>
		<pubDate>Fri, 17 Jul 2009 12:19:42 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://andypike.wordpress.com/?p=52</guid>
		<description><![CDATA[I haven&#8217;t posted in a long time, so I thought it was about time that I did. I decided to take a proper look at Ruby. Currently I know virtually nothing, so I thought I&#8217;d start blogging about my progress which should help me learn and may also help other who are going down the [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=52&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I haven&#8217;t posted in a long time, so I thought it was about time that I did.</p>
<p>I decided to take a proper look at Ruby. Currently I know virtually nothing, so I thought I&#8217;d start blogging about my progress which should help me learn and may also help other who are going down the same path.</p>
<p>Just so you know, I am a .NET developer and all my stuff is Windows based, so all the stuff below works on Windows.</p>
<p><strong>Getting Started</strong></p>
<ol>
<li>First <a href="http://www.ruby-lang.org/en/downloads/" target="_blank">download and install Ruby</a>, I used the Ruby 1.8.6 One-Click Installer.</li>
<li>Read this tutorial on the Ruby site: <a href="http://www.ruby-lang.org/en/documentation/quickstart/" target="_blank">Ruby in Twenty Minutes</a></li>
<li>Next I asked a respected friend (<a href="http://twitter.com/benlovell" target="_blank">@benlovell</a>) what books are worth a look. He listed the following: <a onclick="return mugicPopWin(this,event);" oncontextmenu="mugicRightClick(this);" href="http://www.amazon.co.uk/Well-Grounded-Rubyist-David-Black/dp/1933988657" target="_blank">The Well-Grounded Rubyist</a>, <a onclick="return mugicPopWin(this,event);" oncontextmenu="mugicRightClick(this);" href="http://www.amazon.co.uk/Design-Patterns-Ruby-Addison-Wesley-Professional/dp/0321490452/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1247832717&amp;sr=1-1" target="_blank">Design Patterns in Ruby</a> and <a onclick="return mugicPopWin(this,event);" oncontextmenu="mugicRightClick(this);" href="http://www.amazon.co.uk/Agile-Development-Rails-Pragmatic-Programmers/dp/0977616630/ref=sr_1_12?ie=UTF8&amp;s=books&amp;qid=1247832769&amp;sr=1-12" target="_blank">Agile Web Development with Rails</a>. I&#8217;ve now purchased these, and they look good.</li>
<li>Download and install <a href="http://www.jetbrains.com/ruby/index.html" target="_blank">RubyMine</a> &#8211; this is an IDE by JetBrains that is very nice and as I use Resharper in Visual Studio, the same features are available.</li>
<li>I then took a look at <a href="http://www.pragprog.com/titles/achbd/the-rspec-book" target="_blank">The RSpec Book</a> and purchased that. It&#8217;s pretty good and makes a lot of sense. This will help as I&#8217;m from a TDD background anyway.</li>
</ol>
<p>That&#8217;s about as far as I&#8217;ve got at the moment, in the next post I hope to get some simple RSpec tests in and passing. Wish me luck&#8230;</p>
<div id="_mcePaste" style="overflow:hidden;position:absolute;left:-10000px;top:0;width:1px;height:1px;"><a href="http://rubyforge.org/frs/download.php/47082/ruby186-27_rc2.exe">Ruby 1.8.6 One-Click Installer</a></div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andypike.wordpress.com/52/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andypike.wordpress.com/52/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andypike.wordpress.com/52/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andypike.wordpress.com/52/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andypike.wordpress.com/52/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andypike.wordpress.com/52/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andypike.wordpress.com/52/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andypike.wordpress.com/52/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andypike.wordpress.com/52/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andypike.wordpress.com/52/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andypike.wordpress.com/52/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andypike.wordpress.com/52/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andypike.wordpress.com/52/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andypike.wordpress.com/52/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=52&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andypike.wordpress.com/2009/07/17/learning-ruby/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/196ab25f16dcfd37518a41ceb15e0da0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">andypike</media:title>
		</media:content>
	</item>
		<item>
		<title>Thank you DevEvening</title>
		<link>http://andypike.wordpress.com/2009/03/07/thank-you-devevening/</link>
		<comments>http://andypike.wordpress.com/2009/03/07/thank-you-devevening/#comments</comments>
		<pubDate>Sat, 07 Mar 2009 20:51:18 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://andypike.wordpress.com/2009/03/07/thank-you-devevening/</guid>
		<description><![CDATA[Last Thursday night I gave my first ever technical talk. The subject was “An Introduction to TDD” and I thought it went very well. So a big thank you to everyone that came along and I hope you found the talk and demonstration interesting. So as promised here are the files from Thursday night: PowerPoint [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=51&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Last Thursday night I gave my first ever technical talk. The subject was “An Introduction to TDD” and I thought it went very well. So a big <strong>thank you</strong> to everyone that came along and I hope you found the talk and demonstration interesting.</p>
<p>So as promised here are the files from Thursday night:</p>
<ul>
<li><a href="http://www.andypike.com/IntroductionToTDD.pptx">PowerPoint slides</a> </li>
<li><a href="http://www.andypike.com/DevEvening-IntroToTDD.zip">Source Files</a> </li>
</ul>
<p>Also as promised here are a bunch of links to the various tools I used and spoke about. The ones in bold are the ones that I use, but feel free to look at the others:</p>
<p>Unit Testing Frameworks</p>
<ul>
<li><strong><a href="http://www.nunit.org">NUnit</a></strong> </li>
<li><a href="http://www.mbunit.com">MbUnit</a> </li>
<li><a href="http://www.codeplex.com/xunit">xUnit</a> </li>
<li>MSTest (Part of VS2008 Pro and above)</li>
</ul>
<p>Test Runners</p>
<ul>
<li><strong><a href="http://www.jetbrains.com/resharper">ReSharper</a></strong> (also has the productivity improvements) </li>
<li><strong><a href="http://www.testdriven.net/">TestDriven.NET</a></strong> </li>
</ul>
<p>Mocking Frameworks</p>
<ul>
<li><strong><a href="http://ayende.com/projects/rhino-mocks.aspx">Rhino.Mocks</a></strong> </li>
<li><a href="http://code.google.com/p/moq/">Moq</a> </li>
<li><a href="http://www.typemock.com/">TypeMock</a> </li>
</ul>
<p>UI Testing Frameworks</p>
<ul>
<li><strong><a href="http://watin.sourceforge.net">WatiN</a></strong></li>
<li><a href="http://www.codeplex.com/white">White</a></li>
</ul>
<p>Build Servers</p>
<ul>
<li><strong><a href="http://www.jetbrains.com/teamcity/">TeamCity</a></strong></li>
<li><a href="http://cruisecontrol.sourceforge.net/">CruiseControl.NET</a></li>
<li><a href="http://www.atlassian.com/software/bamboo/">Bamboo</a></li>
</ul>
<p>In addition to this list, I used an <a href="http://www.autohotkey.com/">AutoHotKey</a> script that when run will type an underscore instead of a space which is really handy when writing test and fixture names. <a href="http://davesquared.blogspot.com/2008/05/bdd-test-naming-with-autohotkey.html">You can download it here</a>.</p>
<p>So a big thank again to everyone that came and I hope you learnt something new.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andypike.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andypike.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andypike.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andypike.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andypike.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andypike.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andypike.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andypike.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andypike.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andypike.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andypike.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andypike.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andypike.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andypike.wordpress.com/51/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=51&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andypike.wordpress.com/2009/03/07/thank-you-devevening/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/196ab25f16dcfd37518a41ceb15e0da0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">andypike</media:title>
		</media:content>
	</item>
		<item>
		<title>Presenting at DevEvening</title>
		<link>http://andypike.wordpress.com/2009/02/02/presenting-at-devevening/</link>
		<comments>http://andypike.wordpress.com/2009/02/02/presenting-at-devevening/#comments</comments>
		<pubDate>Mon, 02 Feb 2009 21:03:34 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[DevEvening]]></category>

		<guid isPermaLink="false">http://andypike.wordpress.com/?p=42</guid>
		<description><![CDATA[So I went to my first DevEvening last week and found it very useful. I spoke to a few people about the tools and frameworks I&#8217;ve been working with and found that most people have either never heard of them or have no idea how to use them. After listening to the speakers, I was [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=42&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>So I went to my first <a href="http://devevening.co.uk/">DevEvening</a> last week and found it very useful. I spoke to a few people about the tools and frameworks I&#8217;ve been working with and found that most people have either never heard of them or have no idea how to use them. After listening to the speakers, I was then inspired to present some of the things I do/use during day-to-day development.</p>
<p>So I am going to be presenting at the next <a href="http://devevening.co.uk" target="_blank">DevEvening:</a> &#8220;An Introduction To TDD&#8221; on Thursday 5th March at 7:00pm. I am slightly nervous about this because I haven&#8217;t done any public speaking since I got married 5 years ago and have never presented a technical session of this kind before.</p>
<p>This session will just be an introduction to the subject of Test Driven Development with some general points and a demonstration of my work flow. So if you fancy joining me, please sign up for this free event in Woking and get some more information at <a href="http://devevening.co.uk/">http://devevening.co.uk.</a> Also if there is any area of TDD that you think I should cover for the beginners, please feel free to comment below.</p>
<p>For those that do come, please go easy on me and please no awkward questions ;o)</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andypike.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andypike.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andypike.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andypike.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andypike.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andypike.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andypike.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andypike.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andypike.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andypike.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andypike.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andypike.wordpress.com/42/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andypike.wordpress.com/42/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andypike.wordpress.com/42/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=42&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andypike.wordpress.com/2009/02/02/presenting-at-devevening/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/196ab25f16dcfd37518a41ceb15e0da0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">andypike</media:title>
		</media:content>
	</item>
		<item>
		<title>Integrating Gravatar with Castle MonoRail</title>
		<link>http://andypike.wordpress.com/2009/01/12/integrating-gravatar-with-castle-monorail/</link>
		<comments>http://andypike.wordpress.com/2009/01/12/integrating-gravatar-with-castle-monorail/#comments</comments>
		<pubDate>Mon, 12 Jan 2009 00:56:31 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Castle]]></category>
		<category><![CDATA[MonoRail]]></category>

		<guid isPermaLink="false">http://andypike.wordpress.com/2009/01/12/integrating-gravatar-with-castle-monorail/</guid>
		<description><![CDATA[As part of my experimental Castle MonoRail project that I mentioned last time. I now wanted to allow users to include an image (avatar) within their profile. Obviously I could have just allowed them to upload an image, store it and then shown it when required. But I thought I&#8217;d integrate with Gravatar instead. Gravatar [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=39&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>As part of my experimental <a href="http://www.castleproject.org/" target="_blank">Castle MonoRail</a> project that I mentioned <a href="http://andypike.wordpress.com/2009/01/04/integrating-recaptcha-into-a-monorail-project/" target="_blank">last time</a>. I now wanted to allow users to include an image (avatar) within their profile. Obviously I could have just allowed them to upload an image, store it and then shown it when required. But I thought I&#8217;d integrate with <a href="http://www.gravatar.com" target="_blank">Gravatar</a> instead.</p>
<p><a href="http://www.gravatar.com" target="_blank">Gravatar</a> is basically a free service where anyone can store an avatar image against an email address. They provide a <a href="http://en.gravatar.com/site/implement/url" target="_blank">very simple API</a> for us developer types to integrate with given a user&#8217;s email address. So without further ado, here is what I did:</p>
<p>1. I signed up for a Gravatar account and uploaded an image ready for testing.</p>
<p>2. I created a test (TDD style) for a GravatarHelper class that would at first just return the correct image URL for an email address. I took the test data from their <a href="http://en.gravatar.com/site/implement/url" target="_blank">documentation</a> so I knew it was correct:</p>
<div style="border:1px solid gray;overflow:auto;font-size:8pt;width:97.5%;cursor:text;max-height:200px;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;margin:20px 0 10px;padding:4px;">
<div style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;padding:0;">
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">[TestFixture]</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> When_using_the_gravatar_helper</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">{</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    [Test]</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">void</span> Should_build_a_basic_image_url()</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    {</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">        var gravatar = <span style="color:#0000ff;">new</span> GravatarHelper();</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">        <span style="color:#0000ff;">string</span> url = gravatar.Url(<span style="color:#006080;">" iHaveAn@email.com "</span>);</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;"></pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">        Assert.That(url, Is.EqualTo(<span style="color:#006080;">"http://www.gravatar.com/avatar/3b3be63a4c2a439b013787725dfce802.jpg"</span>));</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    }</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">}</pre>
</div>
</div>
<p>OK, so pretty straightforward there then. The email address is of mixed case and has spaces around it on purpose as the documentation specifies that emails need to be trimmed and lowercased before hashing.</p>
<p>3. Now I have my failing test, I went right ahead and started implementing it:</p>
<div style="border:1px solid gray;overflow:auto;font-size:8pt;width:97.5%;cursor:text;max-height:200px;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;margin:20px 0 10px;padding:4px;">
<div style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;padding:0;">
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> GravatarHelper : AbstractHelper</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">{</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">const</span> <span style="color:#0000ff;">string</span> PROTOCOL = <span style="color:#006080;">"http"</span>;</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">const</span> <span style="color:#0000ff;">string</span> DOMAIN = <span style="color:#006080;">"www.gravatar.com"</span>;</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">const</span> <span style="color:#0000ff;">string</span> PATH = <span style="color:#006080;">"avatar"</span>;</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">const</span> <span style="color:#0000ff;">string</span> EXTENSION = <span style="color:#006080;">"jpg"</span>;</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;"></pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">string</span> Url(<span style="color:#0000ff;">string</span> email)</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    {</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">        email = email.ToLower().Trim();</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;"></pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">        MD5 md5 = <span style="color:#0000ff;">new</span> MD5CryptoServiceProvider();</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">        <span style="color:#0000ff;">byte</span>[] hash = md5.ComputeHash(Encoding.ASCII.GetBytes(email));</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;"></pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">        var hashAsHex = <span style="color:#0000ff;">new</span> StringBuilder();</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">        Array.ForEach(hash, b =&gt; hashAsHex.Append(b.ToString(<span style="color:#006080;">"X2"</span>)));</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;"></pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">        <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">string</span>.Format(<span style="color:#006080;">"{0}://{1}/{2}/{3}.{4}"</span>, PROTOCOL, DOMAIN, PATH, hashAsHex, EXTENSION).ToLower();</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    }</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">}</pre>
</div>
</div>
<p>Again, no rocket science here. I just lowercase and trim the email address then hash it using the built-in .NET MD5 hash provider. Then I have to convert each byte in the hash into hex and add it to a string. Lastly I return the URL that has been built up from the various parts (and lowercased for good measure).</p>
<p>4. Next, just add the helper to my controller:</p>
<div style="border:1px solid gray;overflow:auto;font-size:8pt;width:97.5%;cursor:text;max-height:200px;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;margin:20px 0 10px;padding:4px;">
<div style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;padding:0;">
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">[Helper(<span style="color:#0000ff;">typeof</span>(GravatarHelper), <span style="color:#006080;">"gravatar"</span>)]</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> AccountController : SmartDispatcherController</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">{</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    ...</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">}</pre>
</div>
</div>
<p>5. Then the simple task of using the helper in my view (not my real email):</p>
<div style="border:1px solid gray;overflow:auto;font-size:8pt;width:97.5%;cursor:text;max-height:200px;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;margin:20px 0 10px;padding:4px;">
<div style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;padding:0;">
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">&lt;</span><span style="color:#800000;">img</span> <span style="color:#ff0000;">src</span><span style="color:#0000ff;">="$gravatar.url('someone@somewhere.com')"</span> <span style="color:#0000ff;">/&gt;</span></pre>
</div>
</div>
<p>And hey presto, my Gravatar of my son appeared on my page, wahoo:</p>
<p><a href="http://andypike.files.wordpress.com/2009/01/gravatar.jpg"><img src="http://andypike.files.wordpress.com/2009/01/gravatar-thumb.jpg?w=321&#038;h=169" alt="gravatar" width="321" height="169" /></a></p>
<p>Now that is all very good, but there are some extra parameters that the Gravatar API support. These are size, rating and default (in case the email address isn&#8217;t registered with them). I also wanted the helper to generate the image tag for me. So I went about creating a new helper test:</p>
<div style="border:1px solid gray;overflow:auto;font-size:8pt;width:97.5%;cursor:text;max-height:200px;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;margin:20px 0 10px;padding:4px;">
<div style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;padding:0;">
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">[Test]</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">void</span> Should_build_an_image_url_inside_an_image_tag_with_parameters()</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">{</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    var gravatar = <span style="color:#0000ff;">new</span> GravatarHelper { ServerUtility = <span style="color:#0000ff;">new</span> StubServerUtility() };</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    IDictionary parameters = <span style="color:#0000ff;">new</span> Hashtable</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">                                 {</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">                                     { <span style="color:#006080;">"size"</span>, <span style="color:#006080;">"48"</span> },</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">                                     { <span style="color:#006080;">"default"</span>, <span style="color:#006080;">"http://example.com/images/example.jpg"</span> },</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">                                     { <span style="color:#006080;">"rating"</span>, <span style="color:#006080;">"g"</span> }</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">                                 };</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">string</span> tag = gravatar.Image(<span style="color:#006080;">" iHaveAn@email.com "</span>, parameters);</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    Assert.That(tag, Is.EqualTo(<span style="color:#006080;">"&lt;img src=\"http://www.gravatar.com/avatar/3b3be63a4c2a439b013787725dfce802.jpg?size=48&amp;default=http%3a%2f%2fexample.com%2fimages%2fexample.jpg&amp;rating=g\" alt=\"Gravatar\" /&gt;"</span>));</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">}</pre>
</div>
</div>
<p>I&#8217;m using an IDictionary here so that I can leverage the <a href="http://www.castleproject.org/others/nvelocity/improvements.html" target="_blank">support for it in NVelocity</a>. So about these parameters: The size parameter is the size in pixels that you would like the image (1 to 512) which defaults to 80. The default parameter is a URL of an image in case the email address supplied isn&#8217;t known by Gravatar. The rating parameter can be g, pg, r or x. Also notice in the test the need to set the ServerUtility property of the helper, I just using the StubServerUtility provided by Castle.</p>
<p>Now for the implementation:</p>
<div style="border:1px solid gray;overflow:auto;font-size:8pt;width:97.5%;cursor:text;max-height:200px;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;margin:20px 0 10px;padding:4px;">
<div style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;padding:0;">
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">private</span> <span style="color:#0000ff;">const</span> <span style="color:#0000ff;">string</span> IMAGE_TAG_FORMAT = <span style="color:#006080;">"&lt;img src=\"{0}\" alt=\"Gravatar\" /&gt;"</span>;</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;"></pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">string</span> Url(<span style="color:#0000ff;">string</span> email, IDictionary parameters)</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">{</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">string</span> url = Url(email);</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">string</span> queryString = CommonUtils.BuildQueryString(ServerUtility, parameters, <span style="color:#0000ff;">false</span>);</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;"></pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">string</span>.Concat(url, <span style="color:#006080;">"?"</span>, queryString);</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">}</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;"></pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">string</span> Image(<span style="color:#0000ff;">string</span> email, IDictionary parameters)</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">{</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">return</span> <span style="color:#0000ff;">string</span>.Format(IMAGE_TAG_FORMAT, Url(email, parameters));</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">}</pre>
</div>
</div>
<p>The eagle-eyed amongst you will notice that I&#8217;ve added an overload to the Url method as well that supports parameters (I wrote a test for this first, so don&#8217;t panic). So you can now either create a url with parameters or a full image tag. So now in my view I can do this:</p>
<div style="border:1px solid gray;overflow:auto;font-size:8pt;width:97.5%;cursor:text;max-height:200px;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;margin:20px 0 10px;padding:4px;">
<div style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;padding:0;">
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;"></pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">$gravatar.image("someone@somewhere.com", "%{size='48', rating='g', default='http://example.com/default.jpg'}")</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;"></pre>
</div>
</div>
<p>That about wraps it up for now. I&#8217;ve committed all my code into my Google Code repository, so feel free to have a look: <a title="http://code.google.com/p/andypike/" href="http://code.google.com/p/andypike/">http://code.google.com/p/andypike/</a></p>
<p><a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fandypike.wordpress.com%2f2009%2f01%2f12%2fintegrating-gravatar-with-castle-monorail%2f"><img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fandypike.wordpress.com%2f2009%2f01%2f12%2fintegrating-gravatar-with-castle-monorail%2f" border="0" alt="kick it on DotNetKicks.com" /></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andypike.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andypike.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andypike.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andypike.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andypike.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andypike.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andypike.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andypike.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andypike.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andypike.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andypike.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andypike.wordpress.com/39/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andypike.wordpress.com/39/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andypike.wordpress.com/39/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=39&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andypike.wordpress.com/2009/01/12/integrating-gravatar-with-castle-monorail/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/196ab25f16dcfd37518a41ceb15e0da0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">andypike</media:title>
		</media:content>

		<media:content url="http://andypike.files.wordpress.com/2009/01/gravatar-thumb.jpg" medium="image">
			<media:title type="html">gravatar</media:title>
		</media:content>

		<media:content url="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fandypike.wordpress.com%2f2009%2f01%2f12%2fintegrating-gravatar-with-castle-monorail%2f" medium="image">
			<media:title type="html">kick it on DotNetKicks.com</media:title>
		</media:content>
	</item>
		<item>
		<title>Integrating reCAPTCHA with Castle MonoRail</title>
		<link>http://andypike.wordpress.com/2009/01/04/integrating-recaptcha-into-a-monorail-project/</link>
		<comments>http://andypike.wordpress.com/2009/01/04/integrating-recaptcha-into-a-monorail-project/#comments</comments>
		<pubDate>Sun, 04 Jan 2009 21:54:16 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Castle]]></category>
		<category><![CDATA[MonoRail]]></category>

		<guid isPermaLink="false">http://andypike.wordpress.com/?p=15</guid>
		<description><![CDATA[I&#8217;m currently working on a little experimental Castle MonoRail project and wanted to add a CAPTCHA image to a form. Of course I could try to create my own but I don&#8217;t like reinventing the wheel so I did a little digging and came across reCAPTCHA. It can be integrated into websites and has a [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=15&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m currently working on a little experimental <a href="http://www.castleproject.com" target="_blank">Castle </a><a href="http://www.castleproject.com" target="_blank">MonoRail</a> project and wanted to add a CAPTCHA image to a form. Of course I could try to create my own but I don&#8217;t like reinventing the wheel so I did a little digging and came across <a href="http://recaptcha.net/" target="_blank">reCAPTCHA</a>. It can be integrated into websites and has a number of tools available to help you do this.</p>
<p>I couldn&#8217;t find an example of using it with MonoRail, but did find this <a href="http://devlicio.us/blogs/derik_whittaker/archive/2008/12/02/using-recaptcha-with-asp-net-mvc.aspx" target="_blank">example for ASP.NET MVC by Derik Whittaker</a> which pointed me in the right direction. Here&#8217;s what I did:</p>
<p>1. Sign up to <a href="http://recaptcha.net" target="_blank">reCAPTCHA</a> to obtain my private and public keys. I made this a global account so I can test it on my local server rather than only on an assigned domain.</p>
<p>2. Added the keys to my web.config:</p>
<div style="border:1px solid gray;overflow:auto;font-size:8pt;width:97.5%;cursor:text;max-height:200px;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;margin:20px 0 10px;padding:4px;">
<div style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;padding:0;">
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">&lt;</span><span style="color:#800000;">appSettings</span><span style="color:#0000ff;">&gt;</span></pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">add</span> <span style="color:#ff0000;">key</span><span style="color:#0000ff;">="recaptcha.public"</span> <span style="color:#ff0000;">value</span><span style="color:#0000ff;">="***"</span> <span style="color:#0000ff;">/&gt;</span></pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">&lt;</span><span style="color:#800000;">add</span> <span style="color:#ff0000;">key</span><span style="color:#0000ff;">="recaptcha.private"</span> <span style="color:#ff0000;">value</span><span style="color:#0000ff;">="***"</span> <span style="color:#0000ff;">/&gt;</span></pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">&lt;/</span><span style="color:#800000;">appSettings</span><span style="color:#0000ff;">&gt;</span></pre>
</div>
</div>
<p>3. <a href="http://recaptcha.net/plugins/aspnet/" target="_blank">Downloaded the ASP.NET library</a> and added a reference to the recaptcha.dll assembly.</p>
<p>3. Created a new helper for rendering the control in the view:</p>
<div style="border:1px solid gray;overflow:auto;font-size:8pt;width:97.5%;cursor:text;max-height:200px;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;margin:20px 0 10px;padding:4px;">
<div style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;padding:0;">
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> CaptchaHelper : AbstractHelper</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">{</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">string</span> Render()</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    {</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">        var captchaControl = <span style="color:#0000ff;">new</span> RecaptchaControl {</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">              ID = <span style="color:#006080;">"recaptcha"</span>,</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">              Theme = <span style="color:#006080;">"blackglass"</span>,</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">              PublicKey = ConfigurationManager.AppSettings[<span style="color:#006080;">"recaptcha.public"</span>],</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">              PrivateKey = ConfigurationManager.AppSettings[<span style="color:#006080;">"recaptcha.private"</span>]</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">        };</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">        var htmlWriter = <span style="color:#0000ff;">new</span> HtmlTextWriter( <span style="color:#0000ff;">new</span> StringWriter() );</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">        captchaControl.RenderControl(htmlWriter);</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">        <span style="color:#0000ff;">return</span> htmlWriter.InnerWriter.ToString();</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    }</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">}</pre>
</div>
</div>
<p>4. Added the helper to my controller:</p>
<div style="border:1px solid gray;overflow:auto;font-size:8pt;width:97.5%;cursor:text;max-height:200px;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;margin:20px 0 10px;padding:4px;">
<div style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;padding:0;">
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">[Helper(<span style="color:#0000ff;">typeof</span>(CaptchaHelper), <span style="color:#006080;">"captcha"</span>)]</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> HomeController : SmartDispatcherController</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">{</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    ...</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">}</pre>
</div>
</div>
<p>5. Called the helper inside a form in my view:</p>
<div style="border:1px solid gray;overflow:auto;font-size:8pt;width:97.5%;cursor:text;max-height:200px;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;margin:20px 0 10px;padding:4px;">
<div style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;padding:0;">
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">$captcha.Render()</pre>
</div>
</div>
<p>6. Created a new parameter binder (instead of Derik&#8217;s filter) that determines if the user entered the CAPTCHA code correctly:</p>
<div style="border:1px solid gray;overflow:auto;font-size:8pt;width:97.5%;cursor:text;max-height:200px;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;margin:20px 0 10px;padding:4px;">
<div style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;padding:0;">
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = <span style="color:#0000ff;">false</span>, Inherited = <span style="color:#0000ff;">false</span>)]</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">class</span> CaptchaBindAttribute : Attribute, IParameterBinder</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">{</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">const</span> <span style="color:#0000ff;">string</span> CHALLENGE_FIELD_KEY = <span style="color:#006080;">"recaptcha_challenge_field"</span>;</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">private</span> <span style="color:#0000ff;">const</span> <span style="color:#0000ff;">string</span> RESPONSE_FIELD_KEY = <span style="color:#006080;">"recaptcha_response_field"</span>;</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">object</span> Bind(IEngineContext context, IController controller, IControllerContext controllerContext, ParameterInfo parameterInfo)</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    {</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">        var captchaChallengeValue = context.Request[CHALLENGE_FIELD_KEY];</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">        var captchaResponseValue = context.Request[RESPONSE_FIELD_KEY];</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">        var captchaValidtor = <span style="color:#0000ff;">new</span> Recaptcha.RecaptchaValidator</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">                              {</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">                                  PrivateKey = ConfigurationManager.AppSettings[<span style="color:#006080;">"recaptcha.private"</span>],</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">                                  RemoteIP = context.UnderlyingContext.Request.UserHostAddress,</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">                                  Challenge = captchaChallengeValue,</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">                                  Response = captchaResponseValue</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">                              };</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">        var recaptchaResponse = captchaValidtor.Validate();</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">        <span style="color:#0000ff;">return</span> recaptchaResponse.IsValid;</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    }</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    <span style="color:#0000ff;">public</span> <span style="color:#0000ff;">int</span> CalculateParamPoints(IEngineContext context, IController controller, IControllerContext controllerContext, ParameterInfo parameterInfo)</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">    {</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">        <span style="color:#0000ff;">if</span> (parameterInfo.ParameterType == <span style="color:#0000ff;">typeof</span>(<span style="color:#0000ff;">bool</span>))</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">            <span style="color:#0000ff;">return</span> 10;</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">        <span style="color:#0000ff;">return</span> 0;</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    }</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">}</pre>
</div>
</div>
<p>7. Used the new parameter binder on the receiving controller action to determine if the user passed the CAPTCHA test:</p>
<div style="border:1px solid gray;overflow:auto;font-size:8pt;width:97.5%;cursor:text;max-height:200px;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;margin:20px 0 10px;padding:4px;">
<div style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;padding:0;">
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">[AccessibleThrough(Verb.Post)]</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;"><span style="color:#0000ff;">public</span> <span style="color:#0000ff;">void</span> Register([CaptchaBind]<span style="color:#0000ff;">bool</span> captchaValid)</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">{</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:#f4f4f4;border-style:none;margin:0;padding:0;">    ...</pre>
<pre style="overflow:visible;font-size:8pt;width:100%;color:black;line-height:12pt;font-family:consolas,'Courier New',courier,monospace;background-color:white;border-style:none;margin:0;padding:0;">}</pre>
</div>
</div>
<p>And that&#8217;s about it. I&#8217;ll be releasing this project as open source soon (once I&#8217;ve made some more progress). I&#8217;ve added these components to my AndyPike.Commons assembly which will also be available to those that would like it, but the above code samples should be enough to get you going. Oh, and here is what the view looks like:</p>
<div id="attachment_24" class="wp-caption aligncenter" style="width: 459px"><img class="size-full wp-image-24" title="recaptcha" src="http://andypike.files.wordpress.com/2009/01/recaptcha.gif?w=449&#038;h=326" alt="recaptcha" width="449" height="326" /><p class="wp-caption-text">recaptcha in action</p></div>
<p><a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fandypike.wordpress.com%2f2009%2f01%2f04%2fintegrating-recaptcha-into-a-monorail-project%2f"><img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fandypike.wordpress.com%2f2009%2f01%2f04%2fintegrating-recaptcha-into-a-monorail-project%2f" border="0" alt="kick it on DotNetKicks.com" /></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andypike.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andypike.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andypike.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andypike.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andypike.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andypike.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andypike.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andypike.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andypike.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andypike.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andypike.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andypike.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andypike.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andypike.wordpress.com/15/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=15&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andypike.wordpress.com/2009/01/04/integrating-recaptcha-into-a-monorail-project/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/196ab25f16dcfd37518a41ceb15e0da0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">andypike</media:title>
		</media:content>

		<media:content url="http://andypike.files.wordpress.com/2009/01/recaptcha.gif" medium="image">
			<media:title type="html">recaptcha</media:title>
		</media:content>

		<media:content url="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fandypike.wordpress.com%2f2009%2f01%2f04%2fintegrating-recaptcha-into-a-monorail-project%2f" medium="image">
			<media:title type="html">kick it on DotNetKicks.com</media:title>
		</media:content>
	</item>
		<item>
		<title>First photos of Charlie</title>
		<link>http://andypike.wordpress.com/2009/01/04/first-photos-of-charlie/</link>
		<comments>http://andypike.wordpress.com/2009/01/04/first-photos-of-charlie/#comments</comments>
		<pubDate>Sun, 04 Jan 2009 20:59:03 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[Family]]></category>

		<guid isPermaLink="false">http://andypike.wordpress.com/?p=12</guid>
		<description><![CDATA[Well, Charlie arrived on New Years Day and I thought I&#8217;d upload some photos. Checkout my Flickr account here: http://www.flickr.com/photos/34054727@N08/ So far things are going well, mum and baby are doing fine. He&#8217;s like all babies: sleeps, crys, drinks, poos, sleeps&#8230; Thanks for all the congrats messages and support from friends and family. You guys [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=12&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Well, Charlie arrived on New Years Day and I thought I&#8217;d upload some photos. Checkout my Flickr account here:</p>
<p><a href="http://www.flickr.com/photos/34054727@N08/">http://www.flickr.com/photos/34054727@N08/</a></p>
<p>So far things are going well, mum and baby are doing fine. He&#8217;s like all babies: sleeps, crys, drinks, poos, sleeps&#8230;</p>
<p>Thanks for all the congrats messages and support from friends and family. You guys are really cool.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andypike.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andypike.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andypike.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andypike.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andypike.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andypike.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andypike.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andypike.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andypike.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andypike.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andypike.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andypike.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andypike.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andypike.wordpress.com/12/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=12&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andypike.wordpress.com/2009/01/04/first-photos-of-charlie/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/196ab25f16dcfd37518a41ceb15e0da0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">andypike</media:title>
		</media:content>
	</item>
		<item>
		<title>Welcome to my new blog</title>
		<link>http://andypike.wordpress.com/2009/01/04/my-new-blog/</link>
		<comments>http://andypike.wordpress.com/2009/01/04/my-new-blog/#comments</comments>
		<pubDate>Sun, 04 Jan 2009 12:25:36 +0000</pubDate>
		<dc:creator>Andy</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://andypike.wordpress.com/?p=3</guid>
		<description><![CDATA[Hey all, This is my shiny new blog that is taking over from my old one. I&#8217;ll be posting about all sorts of things but mainly my family and .NET software development. Anyway, stay tuned for more and please update your links. Cheers<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=3&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Hey all,</p>
<p>This is my shiny new blog that is taking over from <a href="http://pixelbugs.wordpress.com" target="_blank">my old one</a>. I&#8217;ll be posting about all sorts of things but mainly my family and .NET software development. Anyway, stay tuned for more and please update your links.</p>
<p>Cheers</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/andypike.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/andypike.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/andypike.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/andypike.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/andypike.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/andypike.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/andypike.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/andypike.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/andypike.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/andypike.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/andypike.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/andypike.wordpress.com/3/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/andypike.wordpress.com/3/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/andypike.wordpress.com/3/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=andypike.wordpress.com&amp;blog=4664176&amp;post=3&amp;subd=andypike&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://andypike.wordpress.com/2009/01/04/my-new-blog/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/196ab25f16dcfd37518a41ceb15e0da0?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">andypike</media:title>
		</media:content>
	</item>
	</channel>
</rss>
