<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
  <channel>
    <title>Michael C. Kennedy's Weblog</title>
    <link>http://www.michaelckennedy.net/blog/</link>
    <description>.NET and Agile Software Design</description>
    <language>en-us</language>
    <copyright>Michael C. Kennedy</copyright>
    <lastBuildDate>Fri, 06 Nov 2009 04:20:00 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.1.8102.813</generator>
    <managingEditor>mkennedy66996693@gmail.com</managingEditor>
    <webMaster>mkennedy66996693@gmail.com</webMaster>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/MichaelCKennedysWeblog" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
      <trackback:ping>http://www.michaelckennedy.net/blog/Trackback.aspx?guid=f334d1de-6875-465f-9837-cc077ea67476</trackback:ping>
      <pingback:server>http://www.michaelckennedy.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.michaelckennedy.net/blog/PermaLink,guid,f334d1de-6875-465f-9837-cc077ea67476.aspx</pingback:target>
      <dc:creator>Michael Kennedy</dc:creator>
      <wfw:comment>http://www.michaelckennedy.net/blog/CommentView,guid,f334d1de-6875-465f-9837-cc077ea67476.aspx</wfw:comment>
      <wfw:commentRss>http://www.michaelckennedy.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=f334d1de-6875-465f-9837-cc077ea67476</wfw:commentRss>
      
      <title>Webcast: Building Modern Apps in ASP.NET WebForms</title>
      <guid isPermaLink="false">http://www.michaelckennedy.net/blog/PermaLink,guid,f334d1de-6875-465f-9837-cc077ea67476.aspx</guid>
      <link>http://feedproxy.google.com/~r/MichaelCKennedysWeblog/~3/7XcePYeUuic/WebcastBuildingModernAppsInASPNETWebForms.aspx</link>
      <pubDate>Fri, 06 Nov 2009 04:20:00 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
At &lt;a href="http://www.develop.com/" target="_blank"&gt;DevelopMentor&lt;/a&gt; we have been&#xD;
running a bunch of &lt;strong&gt;&lt;em&gt;free&lt;/em&gt;&lt;/strong&gt; webcasts. Last month it was &lt;a href="http://www.michaelckennedy.net/blog/2009/11/05/TDDSpaceInvadersVideoAndDownloads.aspx" target="_blank"&gt;TDD&#xD;
and Agile&lt;/a&gt;. This month we are running 4 webcasts celebrating the announcements&#xD;
around .NET 4.0, Visual Studio 2010, and PDC 2009.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Join me Monday, November 23rd and &lt;strong&gt;register here:&lt;/strong&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
     &lt;a title="http://bit.ly/aspwebforms" href="http://bit.ly/aspwebforms" target="_blank"&gt;http://bit.ly/aspwebforms&lt;/a&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
We’ll talk about integrating ASP.NET’s routing infrastructure into existing an ASP.NET&#xD;
WebForms application. This allows you to build SEO websites with URLs like&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
      &lt;a href="http://dotnet.ubbuzz.com/tag/.NET+4.0" target="_blank"&gt;http://dotnet.ubbuzz.com/tag/.NET+4.0&lt;/a&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
while still taking advantage of all the productivity features of WebForms such as&#xD;
post-backs, controls, UpdatePanel, and so on.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
We have room for a couple hundred more attendees so please register and be part of&#xD;
the fun. I promise lots of demos and some&lt;a href="http://apolloideas.com/blog/archives/677" target="_blank"&gt;disdainful&#xD;
comments about PowerPoint&lt;/a&gt;!&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Share it with your friends (social, virtual, real, and other types) using the widgets&#xD;
below!&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;ASP.NET MVC&lt;/strong&gt;: What’s that, you’d rather hear about ASP.NET MVC, not&#xD;
this creaky old WebForms stuff? That’s Brock Allen’s talk: &lt;a title="http://bit.ly/intromvc" href="http://bit.ly/intromvc" target="_blank"&gt;http://bit.ly/intromvc&lt;/a&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;strong&gt;WF 4&lt;/strong&gt;: Is WF 4 and visual programming your thing? Check out &lt;a href="http://msmvps.com/blogs/theproblemsolver/default.aspx" target="_blank"&gt;Maurice&#xD;
de Beijer&lt;/a&gt;’s WF 4 talk: &lt;a title="http://bit.ly/meetwf4" href="http://bit.ly/meetwf4"&gt;http://bit.ly/meetwf4&lt;/a&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
New Parallel Extensions your thing: Check out &lt;a href="http://andyclymer.blogspot.com/" target="_blank"&gt;Andy&#xD;
Clymer&lt;/a&gt;’s PFX talk. (link to follow soon).&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Cheers, &#xD;
&lt;br&gt;&#xD;
Michael&#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.michaelckennedy.net/blog/aggbug.ashx?id=f334d1de-6875-465f-9837-cc077ea67476"&gt;&lt;/img&gt;&#xD;
        &lt;br&gt;&#xD;
        &lt;hr&gt;&lt;/hr&gt;&#xD;
All content copyright Michael C. Kennedy. All information, source code, and especially&#xD;
tools are provided as is and on a "use at your own risk" basis.&lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=7XcePYeUuic:116nqCHd3hU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=7XcePYeUuic:116nqCHd3hU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=7XcePYeUuic:116nqCHd3hU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=7XcePYeUuic:116nqCHd3hU:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=7XcePYeUuic:116nqCHd3hU:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=7XcePYeUuic:116nqCHd3hU:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=7XcePYeUuic:116nqCHd3hU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=7XcePYeUuic:116nqCHd3hU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=7XcePYeUuic:116nqCHd3hU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=7XcePYeUuic:116nqCHd3hU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=7XcePYeUuic:116nqCHd3hU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MichaelCKennedysWeblog/~4/7XcePYeUuic" height="1" width="1"/&gt;</description>
      <comments>http://www.michaelckennedy.net/blog/CommentView,guid,f334d1de-6875-465f-9837-cc077ea67476.aspx</comments>
      <category>ASP.NET</category>
      <category>DevelopMentor</category>
      <category>Screencasts</category>
      <category>Talks</category>
      <category>Visual Studio</category>
    <feedburner:origLink>http://www.michaelckennedy.net/blog/2009/11/06/WebcastBuildingModernAppsInASPNETWebForms.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.michaelckennedy.net/blog/Trackback.aspx?guid=00efd6df-328b-4069-8fb8-4189507998e1</trackback:ping>
      <pingback:server>http://www.michaelckennedy.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.michaelckennedy.net/blog/PermaLink,guid,00efd6df-328b-4069-8fb8-4189507998e1.aspx</pingback:target>
      <dc:creator>Michael Kennedy</dc:creator>
      <wfw:comment>http://www.michaelckennedy.net/blog/CommentView,guid,00efd6df-328b-4069-8fb8-4189507998e1.aspx</wfw:comment>
      <wfw:commentRss>http://www.michaelckennedy.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=00efd6df-328b-4069-8fb8-4189507998e1</wfw:commentRss>
      
      <title>TDD Space Invaders Video and Downloads</title>
      <guid isPermaLink="false">http://www.michaelckennedy.net/blog/PermaLink,guid,00efd6df-328b-4069-8fb8-4189507998e1.aspx</guid>
      <link>http://feedproxy.google.com/~r/MichaelCKennedysWeblog/~3/nQT6etmgTuk/TDDSpaceInvadersVideoAndDownloads.aspx</link>
      <pubDate>Thu, 05 Nov 2009 07:17:00 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
Recently &lt;a href="http://twitter.com/isidore_us" target="_blank"&gt;Llewellyn Falco&lt;/a&gt; and&#xD;
I did a webcast for &lt;a href="http://www.develop.com/" target="_blank"&gt;DevelopMentor&lt;/a&gt; where&#xD;
we demonstrated some TDD techniques and introduced &lt;a href="http://approvaltests.sourceforge.net/" target="_blank"&gt;Approval&#xD;
Tests&lt;/a&gt;. We let the audience choose our project and they chose Space Invaders. It&#xD;
was all great fun. Now the videos and MP3 streams are online and available for download.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a title="Watch Streaming Video (WMV HQ)" href="http://www.michaelckennedy.com/Downloads/DevelopMentor/TDD-Falco-Kennedy-DevelopMentor-2009-10-27.wvx"&gt;&#xD;
            &lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Watch streaming video (WMV HQ)" border="0" alt="Watch streaming video (WMV HQ)" src="http://www.michaelckennedy.net/blog/content/binary/WindowsLiveWriter/TDDSpaceInvadersVideoandDownloads_F36E/TddVideoScreenShot_3.png" width="242" height="188"&gt;&lt;/img&gt;&#xD;
          &lt;/a&gt;&#xD;
          &lt;br&gt;&#xD;
          &lt;a title="Watch streaming video (WMV HQ)" href="http://www.michaelckennedy.com/Downloads/DevelopMentor/TDD-Falco-Kennedy-DevelopMentor-2009-10-27.wvx"&gt;&#xD;
            &lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Watch streaming video (WMV HQ)" border="0" alt="Watch streaming video (WMV HQ)" src="http://www.michaelckennedy.net/blog/content/binary/WindowsLiveWriter/TDDSpaceInvadersVideoandDownloads_F36E/WmvIcon_3.png" width="57" height="48"&gt;&lt;/img&gt;&#xD;
          &lt;/a&gt;   &lt;a title="Download WMV Video" href="http://www.michaelckennedy.com/Downloads/DevelopMentor/TDD-Falco-Kennedy-DevelopMentor-2009-10-27.zip"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Download WMV Video" border="0" alt="Download WMV Video" src="http://www.michaelckennedy.net/blog/content/binary/WindowsLiveWriter/TDDSpaceInvadersVideoandDownloads_F36E/ZipIcon_9.png" width="47" height="48"&gt;&lt;/img&gt;&lt;/a&gt;&lt;a title="Listen to MP3 Streaming" href="http://www.michaelckennedy.com/Downloads/DevelopMentor/TDD-Falco-Kennedy-DevelopMentor-2009-10-27.mp3" target="_blank"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Listen to MP3 Streaming" border="0" alt="Listen to MP3 Streaming" src="http://www.michaelckennedy.net/blog/content/binary/WindowsLiveWriter/TDDSpaceInvadersVideoandDownloads_F36E/Mp3Icon_5.png" width="43" height="48"&gt;&lt;/img&gt;&lt;/a&gt;&lt;a title="Download MP3" href="http://www.michaelckennedy.com/Downloads/DevelopMentor/TDD-Falco-Kennedy-DevelopMentor-2009-10-27-mp3only.zip"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Download MP3" border="0" alt="Download MP3" src="http://www.michaelckennedy.net/blog/content/binary/WindowsLiveWriter/TDDSpaceInvadersVideoandDownloads_F36E/ZipIcon_10.png" width="47" height="48"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Be sure to check out the write-up we did afterward where we talked about the tools&#xD;
and gave you a chance to try it for yourself:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
   &lt;a href="http://www.michaelckennedy.net/blog/2009/10/28/TDDInvadesSpaceInvaders.aspx" target="_blank"&gt;TDD&#xD;
Space Invaders Write-up&lt;/a&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
You can also watch two other, higher level agile webcasts by Bill Nazzaro here:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
   &lt;a href="http://www.develop.com/agilewebinars" target="_blank"&gt;Agile&#xD;
Webcasts at DevelopMentor&lt;/a&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Cheers! &#xD;
&lt;br&gt;&#xD;
Michael &#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.michaelckennedy.net/blog/aggbug.ashx?id=00efd6df-328b-4069-8fb8-4189507998e1"&gt;&lt;/img&gt;&#xD;
        &lt;br&gt;&#xD;
        &lt;hr&gt;&lt;/hr&gt;&#xD;
All content copyright Michael C. Kennedy. All information, source code, and especially&#xD;
tools are provided as is and on a "use at your own risk" basis.&lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=nQT6etmgTuk:1tUBhVmEvUE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=nQT6etmgTuk:1tUBhVmEvUE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=nQT6etmgTuk:1tUBhVmEvUE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=nQT6etmgTuk:1tUBhVmEvUE:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=nQT6etmgTuk:1tUBhVmEvUE:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=nQT6etmgTuk:1tUBhVmEvUE:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=nQT6etmgTuk:1tUBhVmEvUE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=nQT6etmgTuk:1tUBhVmEvUE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=nQT6etmgTuk:1tUBhVmEvUE:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=nQT6etmgTuk:1tUBhVmEvUE:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=nQT6etmgTuk:1tUBhVmEvUE:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MichaelCKennedysWeblog/~4/nQT6etmgTuk" height="1" width="1"/&gt;</description>
      <comments>http://www.michaelckennedy.net/blog/CommentView,guid,00efd6df-328b-4069-8fb8-4189507998e1.aspx</comments>
      <category>DevelopMentor</category>
      <category>Screencasts</category>
      <category>Talks</category>
      <category>Unit Testing</category>
    <feedburner:origLink>http://www.michaelckennedy.net/blog/2009/11/05/TDDSpaceInvadersVideoAndDownloads.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.michaelckennedy.net/blog/Trackback.aspx?guid=11aae2fd-cddf-4cf8-a789-b7860f1e5738</trackback:ping>
      <pingback:server>http://www.michaelckennedy.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.michaelckennedy.net/blog/PermaLink,guid,11aae2fd-cddf-4cf8-a789-b7860f1e5738.aspx</pingback:target>
      <dc:creator>Michael Kennedy</dc:creator>
      <wfw:comment>http://www.michaelckennedy.net/blog/CommentView,guid,11aae2fd-cddf-4cf8-a789-b7860f1e5738.aspx</wfw:comment>
      <wfw:commentRss>http://www.michaelckennedy.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=11aae2fd-cddf-4cf8-a789-b7860f1e5738</wfw:commentRss>
      <title>TDD Invades Space Invaders</title>
      <guid isPermaLink="false">http://www.michaelckennedy.net/blog/PermaLink,guid,11aae2fd-cddf-4cf8-a789-b7860f1e5738.aspx</guid>
      <link>http://feedproxy.google.com/~r/MichaelCKennedysWeblog/~3/QRoYBdesj8o/TDDInvadesSpaceInvaders.aspx</link>
      <pubDate>Wed, 28 Oct 2009 21:13:21 GMT</pubDate>
      <description>A joint post by Llewellyn Falco and Michael Kennedy&lt;br /&gt;
&lt;br /&gt;
[Update: Get &lt;a href="http://www.michaelckennedy.net/blog/2009/11/05/TDDSpaceInvadersVideoAndDownloads.aspx" target="_blank"&gt;the
videos and additional downloads&lt;/a&gt; for this webcast.]&lt;br /&gt;
&lt;br /&gt;
As a follow-up to our "&lt;a href="http://www.michaelckennedy.net/blog/2009/08/08/ArticleAvoiding5CommonPitfallsInUnitTesting.aspx"&gt;Avoiding
5 Common Pitfalls in Unit Testing&lt;/a&gt;" article we did a webcast where we took a problem
from the audience and solved it live and unrehearsed on stage. These kinds of performances
are always a risk but that's part of what makes them fun. 
&lt;br /&gt;
&lt;br /&gt;
Of course, the question is could we have done it better? Here's your chance to try
it for yourself (details below). 
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;The Problem&lt;/b&gt;: 
&lt;br /&gt;
&lt;br /&gt;
Our viewers chose to have us build the game &lt;i&gt;&lt;b&gt;Space Invaders&lt;/b&gt;&lt;/i&gt;. The first
thing we had to do to sketch out a basic scenario we could implement. We started with
a picture to remind what Space Invaders even was: 
&lt;br /&gt;
&lt;br /&gt;
&lt;img border="1" src="http://www.michaelckennedy.net/blog/content/binary/QuickOverviewWhiteBoardForSpaceInvaders.png" /&gt; 
&lt;br /&gt;
&lt;br /&gt;
This was too big of a scenario for us to tackle in the allotted 40 minutes for programming.
So then we started by creating a simpler scenario which we sketched out on the "whiteboard": 
&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.michaelckennedy.net/blog/content/binary/ReceiptForSpaceInvaders.png" target="_blank"&gt;&lt;img border="1" src="http://www.michaelckennedy.net/blog/content/binary/ReceiptForSpaceInvaders_Thumb.png" /&gt;&lt;/a&gt; 
&lt;br /&gt;
&lt;a href="http://www.michaelckennedy.net/blog/content/binary/ReceiptForSpaceInvaders.png" target="_blank"&gt;Click
for full size image.&lt;/a&gt; 
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt; 
&lt;br /&gt;
Flushing Out the Scenario&lt;/b&gt;: 
&lt;br /&gt;
&lt;blockquote&gt;In doing this, a couple of things were revealed about the game. 
&lt;br /&gt;
&lt;br /&gt;
First, we wanted to make the tank and aliens all be the same size so we could put
them on a grid. But then we saw that our bullet wouldn't fit that story, so we introduced
the idea of relative sizes. We also realized that even though we drew the block, it
was too complex for the first scenario and it would have to wait. 
&lt;br /&gt;
&lt;br /&gt;
Notice that as we started writing the scenario in English, there are mistakes, irrelevancies,
and problems with the order. This is OK. The thing to remember is that all of this
was done for the sole purpose of creating a recipe for a scenario we could test. That
scenario is the following: 
&lt;br /&gt;
&lt;/blockquote&gt; &lt;pre class="brush: csharp"&gt;[TestMethod]
public void TestSimpleKill()
{
   // 1. Create a 15x10 board.
   // 2. Place a 3x2 tank at 1x8.
   // 3. Place a 2x2 alien at 7x3 heading west.
   // 4. tank shoots
   // 5. advance 4 turns
   // 6. not won
   // 7. advance
   // 8. win
}&lt;/pre&gt;
&lt;p&gt;
Now that we had the recipe, we could go about writing the code. 
&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;
Here's your chance to &lt;b&gt;play at home&lt;/b&gt;! 
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Set your timer to 40 minutes.&lt;/li&gt;
&lt;li&gt;
Create a new test project.&lt;/li&gt;
&lt;li&gt;
Paste that method above.&lt;/li&gt;
&lt;li&gt;
Translate the comments into code.&lt;/li&gt;
&lt;/ol&gt;
If you believe there's a better process, we invite you to try that as well. 
&lt;br /&gt;
&lt;br /&gt;
We made it to step 4 during our presentation (download code below) and estimate another
15 minutes would have had the whole scenario done, tested, and well-factored. 
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Stories vs. Requirements&lt;/b&gt; (stories win): 
&lt;br /&gt;
&lt;br /&gt;
We'd like to point out a couple of things about the story. First, it was quick to
write the story. We did it in 5 minutes. Second, it translates well to code because
it has behavior and objects working together. Let's compare that to the requirements
that this story flushed-out. 
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;ul&gt;
&lt;li&gt;
Need a board&lt;/li&gt;
&lt;li&gt;
Boards should have width &amp; height&lt;/li&gt;
&lt;li&gt;
Boards contain game objects&lt;/li&gt;
&lt;li&gt;
Game objects have a witdth, height&lt;/li&gt;
&lt;li&gt;
Game objects have the ability to move each turn&lt;/li&gt;
&lt;li&gt;
Aliens move either left or right each turn&lt;/li&gt;
&lt;li&gt;
Bullets move either up or down each turn&lt;/li&gt;
&lt;li&gt;
Bullets are 1x1&lt;/li&gt;
&lt;li&gt;
Tanks are 3x2&lt;/li&gt;
&lt;li&gt;
Aliens are 2x2&lt;/li&gt;
&lt;li&gt;
The game is not won until all the aliens are killed&lt;/li&gt;
&lt;li&gt;
The game is won if alll the aliens are killed&lt;/li&gt;
&lt;li&gt;
An Alien is killed if it is hit by a bullet&lt;/li&gt;
&lt;li&gt;
Tanks can fire&lt;/li&gt;
&lt;li&gt;
Firing with a tank creates a bullet going up from the space directly above the tank&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
Now we want to point out that this requirements doc is much hard to understand than
our story. For example, if you were to add more requirements (e.g. an alien also shoots)
is that easy to determine whether we have complete requirements? It also takes much
more effort to create and especially to tell if it is complete. People aren't made
to handle requirement documents well but we are story-telling machines. We embrace
this in our coding techniques. 
&lt;br /&gt;
&lt;br /&gt;
We'd also like to mention some of the tools discussed at the end. 
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;For remote collaboration we use&lt;/b&gt;: 
&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.skype.com/" target="_blank"&gt;Skype &lt;/a&gt;(audio / video) 
&lt;br /&gt;
&lt;a href="http://www.realvnc.com/" target="_blank"&gt;VNC &lt;/a&gt;for screen keyboard sharing 
&lt;br /&gt;
&lt;a href="http://windows.microsoft.com/en-US/windows-vista/Remote-Desktop-Connection-frequently-asked-questions" target="_blank"&gt;RDP &lt;/a&gt;(windows
remote desktop) -- requires Windows 2003/2008 server for pairing. 
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Source Control&lt;/b&gt;: 
&lt;br /&gt;
&lt;a href="http://tortoisesvn.tigris.org/" target="_blank"&gt;TortoiseSVN&lt;/a&gt; 
&lt;br /&gt;
&lt;a href="http://code.google.com/p/tortoisegit/" target="_blank"&gt;TortoiseGit&lt;/a&gt; 
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Developer Tools&lt;/b&gt;: 
&lt;br /&gt;
&lt;a href="http://www.jetbrains.com/resharper/" target="_blank"&gt;Resharper&lt;/a&gt; 
&lt;br /&gt;
&lt;a href="http://www.devexpress.com/Products/Visual_Studio_Add-in/Coding_Assistance/" target="_blank"&gt;CodeRush&lt;/a&gt; 
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Testing Tools&lt;/b&gt;: 
&lt;br /&gt;
&lt;a href="http://msdn.microsoft.com/en-us/vstudio/default.aspx" target="_blank"&gt;MsTest&lt;/a&gt; (in
Visual Studio Professional and up) 
&lt;br /&gt;
&lt;a href="http://www.nunit.org/index.php" target="_blank"&gt;NUnit&lt;/a&gt; 
&lt;br /&gt;
&lt;a href="http://www.ncover.com/" target="_blank"&gt;NCover &lt;/a&gt; 
&lt;br /&gt;
&lt;a href="http://tortoisesvn.tigris.org/TortoiseIDiff.html" target="_blank"&gt;TortioseDiff&lt;/a&gt; 
&lt;br /&gt;
&lt;a href="http://approvaltests.com" target="_blank"&gt;Approvals Tests&lt;/a&gt; 
&lt;br /&gt;
&lt;a href="http://sourceforge.net/projects/approvaltests/files/" target="_blank"&gt;Approvals
Tests&lt;/a&gt; CodeRush add-in 
&lt;br /&gt;
&lt;a href="http://www.ayende.com/projects/rhino-mocks.aspx" target="_blank"&gt;Rhino Mock&lt;/a&gt; 
&lt;br /&gt;
&lt;a href="http://learn.typemock.com/index2/" target="_blank"&gt;TypeMock&lt;/a&gt; 
&lt;br /&gt;
&lt;br /&gt;
If you try this scenario yourself, please leave a comment about your experience. 
&lt;br /&gt;
&lt;br /&gt;
Download the code and slides from the webcast here: 
&lt;br /&gt;
&lt;br /&gt;
Code: &lt;a href="http://www.michaelckennedy.com/Downloads/DevelopMentor/TddWithLlewellynAndMichael.zip" target="_blank"&gt;TddWithLlewellynAndMichael.zip&lt;/a&gt; 
&lt;br /&gt;
Slides &lt;a href="http://www.michaelckennedy.com/Downloads/DevelopMentor/dmtdd.pdf" target="_blank"&gt;dmtdd.pdf&lt;/a&gt; 
&lt;br /&gt;
&lt;br /&gt;
Cheers -- &lt;a href="http://twitter.com/mkennedy" target="_blank"&gt;Michael&lt;/a&gt; and &lt;a href="http://twitter.com/isidore_us" target="_blank"&gt;Llewellyn&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.michaelckennedy.net/blog/aggbug.ashx?id=11aae2fd-cddf-4cf8-a789-b7860f1e5738" /&gt;
&lt;br /&gt;
&lt;hr /&gt;All content copyright Michael C. Kennedy. All information, source code, and especially tools are provided as is and on a "use at your own risk" basis.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=QRoYBdesj8o:aLWTH95Z0ko:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=QRoYBdesj8o:aLWTH95Z0ko:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=QRoYBdesj8o:aLWTH95Z0ko:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=QRoYBdesj8o:aLWTH95Z0ko:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=QRoYBdesj8o:aLWTH95Z0ko:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=QRoYBdesj8o:aLWTH95Z0ko:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=QRoYBdesj8o:aLWTH95Z0ko:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=QRoYBdesj8o:aLWTH95Z0ko:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=QRoYBdesj8o:aLWTH95Z0ko:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=QRoYBdesj8o:aLWTH95Z0ko:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=QRoYBdesj8o:aLWTH95Z0ko:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MichaelCKennedysWeblog/~4/QRoYBdesj8o" height="1" width="1"/&gt;</description>
      <comments>http://www.michaelckennedy.net/blog/CommentView,guid,11aae2fd-cddf-4cf8-a789-b7860f1e5738.aspx</comments>
      <category>DevelopMentor</category>
      <category>Screencasts</category>
      <category>Talks</category>
      <category>Unit Testing</category>
    <feedburner:origLink>http://www.michaelckennedy.net/blog/2009/10/28/TDDInvadesSpaceInvaders.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.michaelckennedy.net/blog/Trackback.aspx?guid=ea540aa3-51bc-4bbd-9779-36f14715f626</trackback:ping>
      <pingback:server>http://www.michaelckennedy.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.michaelckennedy.net/blog/PermaLink,guid,ea540aa3-51bc-4bbd-9779-36f14715f626.aspx</pingback:target>
      <dc:creator>Michael Kennedy</dc:creator>
      <wfw:comment>http://www.michaelckennedy.net/blog/CommentView,guid,ea540aa3-51bc-4bbd-9779-36f14715f626.aspx</wfw:comment>
      <wfw:commentRss>http://www.michaelckennedy.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=ea540aa3-51bc-4bbd-9779-36f14715f626</wfw:commentRss>
      <slash:comments>3</slash:comments>
      
      <title>Attend My Live, Free TDD Webinar with Llewellyn Falco and Myself at 10am Tomorrow!</title>
      <guid isPermaLink="false">http://www.michaelckennedy.net/blog/PermaLink,guid,ea540aa3-51bc-4bbd-9779-36f14715f626.aspx</guid>
      <link>http://feedproxy.google.com/~r/MichaelCKennedysWeblog/~3/azDAk4VHboc/AttendMyLiveFreeTDDWebinarWithLlewellynFalcoAndMyselfAt10amTomorrow.aspx</link>
      <pubDate>Mon, 26 Oct 2009 23:29:46 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
[Update: See the follow-up post here: &lt;a href="http://www.michaelckennedy.net/blog/2009/10/28/TDDInvadesSpaceInvaders.aspx"&gt;TDD&#xD;
Invades Space Invaders&lt;/a&gt;]&lt;br&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Tuesday, October 27, 2009 at &lt;b&gt;10am Pacific time &lt;/b&gt;&lt;a href="http://twitter.com/isidore_us" target="_blank"&gt;Llewellyn&#xD;
Falco&lt;/a&gt; and I will be giving a &lt;i&gt;live, unscripted, and no safety-net demonstration&lt;/i&gt; of&#xD;
Test Driven Development (TDD) as part of the &lt;a href="http://www.develop.com/" target="_blank"&gt;DevelopMentor&lt;/a&gt; webinar&#xD;
series (this particular series is a 3-part series on Agile development).&lt;br&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
We already have a bunch of attendees registered. But we have room for as many of you&#xD;
who are interested in agile and TDD. Sign up here:&lt;br&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
   &lt;a target="_blank" href="http://bit.ly/dm-tdd-m-and-l"&gt;http://bit.ly/dm-tdd-m-and-l&lt;/a&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
In addition to core TDD techniques, you will see how an amazing technique and set&#xD;
of tools designed by Llewellyn called &lt;a href="http://approvaltests.sourceforge.net/" target="_blank"&gt;Approval&#xD;
Tests&lt;/a&gt; makes writing tests as simple as verifying an image or text file. Tired&#xD;
of writing 50 lines of test code for every 50 lines of production code but you still&#xD;
want the power of TDD? You need to learn more about Approvals and we'll demo that&#xD;
live tomorrow!&lt;br&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
I hope to see you all online. Feel free to help me get the word out by tweeting this&#xD;
or shouting it (see icons below).&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Cheers, Michael.&lt;br&gt;&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.michaelckennedy.net/blog/aggbug.ashx?id=ea540aa3-51bc-4bbd-9779-36f14715f626"&gt;&lt;/img&gt;&#xD;
        &lt;br&gt;&#xD;
        &lt;hr&gt;&lt;/hr&gt;&#xD;
All content copyright Michael C. Kennedy. All information, source code, and especially&#xD;
tools are provided as is and on a "use at your own risk" basis.&lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=azDAk4VHboc:GaPZDQTfF7s:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=azDAk4VHboc:GaPZDQTfF7s:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=azDAk4VHboc:GaPZDQTfF7s:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=azDAk4VHboc:GaPZDQTfF7s:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=azDAk4VHboc:GaPZDQTfF7s:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=azDAk4VHboc:GaPZDQTfF7s:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=azDAk4VHboc:GaPZDQTfF7s:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=azDAk4VHboc:GaPZDQTfF7s:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=azDAk4VHboc:GaPZDQTfF7s:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=azDAk4VHboc:GaPZDQTfF7s:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=azDAk4VHboc:GaPZDQTfF7s:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MichaelCKennedysWeblog/~4/azDAk4VHboc" height="1" width="1"/&gt;</description>
      <comments>http://www.michaelckennedy.net/blog/CommentView,guid,ea540aa3-51bc-4bbd-9779-36f14715f626.aspx</comments>
      <category>DevelopMentor</category>
      <category>Open Source</category>
      <category>Screencasts</category>
      <category>Talks</category>
      <category>Tools</category>
      <category>Unit Testing</category>
    <feedburner:origLink>http://www.michaelckennedy.net/blog/2009/10/26/AttendMyLiveFreeTDDWebinarWithLlewellynFalcoAndMyselfAt10amTomorrow.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.michaelckennedy.net/blog/Trackback.aspx?guid=92ba76c3-8643-4904-9f25-5bd40f5833b5</trackback:ping>
      <pingback:server>http://www.michaelckennedy.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.michaelckennedy.net/blog/PermaLink,guid,92ba76c3-8643-4904-9f25-5bd40f5833b5.aspx</pingback:target>
      <dc:creator>Michael Kennedy</dc:creator>
      <wfw:comment>http://www.michaelckennedy.net/blog/CommentView,guid,92ba76c3-8643-4904-9f25-5bd40f5833b5.aspx</wfw:comment>
      <wfw:commentRss>http://www.michaelckennedy.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=92ba76c3-8643-4904-9f25-5bd40f5833b5</wfw:commentRss>
      
      <title>Boot to VHD Screencast</title>
      <guid isPermaLink="false">http://www.michaelckennedy.net/blog/PermaLink,guid,92ba76c3-8643-4904-9f25-5bd40f5833b5.aspx</guid>
      <link>http://feedproxy.google.com/~r/MichaelCKennedysWeblog/~3/CQ2XBIDPs9Q/BootToVHDScreencast.aspx</link>
      <pubDate>Tue, 20 Oct 2009 04:50:49 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;b&gt;WARNING&lt;/b&gt;: This is some advanced stuff. It's not that hard, but you can break&#xD;
things that are hard to fix. So, there is no warranty express or implied. Windows&#xD;
7 or Windows 2008 Server R2 are required.&lt;br&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Have you heard of the new feature in Windows 7 and Server 2008 R2 called Boot to VHD?&#xD;
It is amazing! But it's one of those concepts that people hear about and think "hmm,&#xD;
interesting." But when people see it in action it's "OMG, I must have this!" &#xD;
&lt;br&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
I recently had that experience myself and enough people asked me about it that I decided&#xD;
to do a quick (15 min) screencast how to setup a native boot to virtual hard drives.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
If you want a great overview and step-by-step instructions, check out Scott Hanselman's&#xD;
blog post:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
   &lt;a href="http://www.hanselman.com/blog/LessVirtualMoreMachineWindows7AndTheMagicOfBootToVHD.aspx" target="_blank"&gt;Less&#xD;
Virtual, More Machine - Windows 7 and the magic of Boot to VHD&lt;br&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
If you want to see boot to VHD in action, then check out the video here:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;a href="http://www.michaelckennedy.com/Downloads/videos/BootToVhdKennedyWalkthrough.zip" target="_blank"&gt;&#xD;
            &lt;img src="http://www.michaelckennedy.net/blog/content/binary/WalkthoughScreenShot.png" border="0"&gt;&lt;/img&gt;&#xD;
          &lt;/a&gt;&#xD;
          &lt;br&gt;&#xD;
          &lt;br&gt;&#xD;
Download Screencast: &lt;a href="http://www.michaelckennedy.com/Downloads/videos/BootToVhdKennedyWalkthrough.zip" target="_blank"&gt;BootToVhdKennedyWalkthrough.zip&lt;/a&gt; (339&#xD;
MB)&#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.michaelckennedy.net/blog/aggbug.ashx?id=92ba76c3-8643-4904-9f25-5bd40f5833b5"&gt;&lt;/img&gt;&#xD;
        &lt;br&gt;&#xD;
        &lt;hr&gt;&lt;/hr&gt;&#xD;
All content copyright Michael C. Kennedy. All information, source code, and especially&#xD;
tools are provided as is and on a "use at your own risk" basis.&lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=CQ2XBIDPs9Q:5PaWBMenFOw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=CQ2XBIDPs9Q:5PaWBMenFOw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=CQ2XBIDPs9Q:5PaWBMenFOw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=CQ2XBIDPs9Q:5PaWBMenFOw:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=CQ2XBIDPs9Q:5PaWBMenFOw:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=CQ2XBIDPs9Q:5PaWBMenFOw:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=CQ2XBIDPs9Q:5PaWBMenFOw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=CQ2XBIDPs9Q:5PaWBMenFOw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=CQ2XBIDPs9Q:5PaWBMenFOw:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=CQ2XBIDPs9Q:5PaWBMenFOw:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=CQ2XBIDPs9Q:5PaWBMenFOw:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MichaelCKennedysWeblog/~4/CQ2XBIDPs9Q" height="1" width="1"/&gt;</description>
      <comments>http://www.michaelckennedy.net/blog/CommentView,guid,92ba76c3-8643-4904-9f25-5bd40f5833b5.aspx</comments>
      <category>Screencasts</category>
    <feedburner:origLink>http://www.michaelckennedy.net/blog/2009/10/20/BootToVHDScreencast.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.michaelckennedy.net/blog/Trackback.aspx?guid=b337cd7c-528d-4e47-a3c9-736c45c35d6d</trackback:ping>
      <pingback:server>http://www.michaelckennedy.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.michaelckennedy.net/blog/PermaLink,guid,b337cd7c-528d-4e47-a3c9-736c45c35d6d.aspx</pingback:target>
      <dc:creator>Michael Kennedy</dc:creator>
      <wfw:comment>http://www.michaelckennedy.net/blog/CommentView,guid,b337cd7c-528d-4e47-a3c9-736c45c35d6d.aspx</wfw:comment>
      <wfw:commentRss>http://www.michaelckennedy.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=b337cd7c-528d-4e47-a3c9-736c45c35d6d</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <title>Article: Avoiding 5 Common Pitfalls in Unit Testing</title>
      <guid isPermaLink="false">http://www.michaelckennedy.net/blog/PermaLink,guid,b337cd7c-528d-4e47-a3c9-736c45c35d6d.aspx</guid>
      <link>http://feedproxy.google.com/~r/MichaelCKennedysWeblog/~3/bOqt0E60kiM/ArticleAvoiding5CommonPitfallsInUnitTesting.aspx</link>
      <pubDate>Sat, 08 Aug 2009 00:40:13 GMT</pubDate>
      <description>&lt;div&gt;Llewellyn Falco and I recently wrote an article for DevelopMentor's Developments
newsletter entitled &lt;u&gt;&lt;i&gt;Avoiding 5 Common Pitfalls in Unit Testing&lt;/i&gt;&lt;/u&gt;. 
&lt;br /&gt;
&lt;br /&gt;
You can read it at the DevelopMentor website: 
&lt;br /&gt;
&lt;br /&gt;
&amp;#160;&amp;#160; &lt;a href="http://www.develop.com/testingpitfalls" target="_blank"&gt;http://www.develop.com/testingpitfalls &lt;/a&gt; 
&lt;br /&gt;
&lt;br /&gt;
I've republished here for my readers. Enjoy! 
&lt;br /&gt;
&lt;br /&gt;
[Update: We have also done a webcast demonstrating some of these ideas, which we wrote
up here: 
&lt;br /&gt;
&lt;a href="http://www.michaelckennedy.net/blog/2009/10/28/TDDInvadesSpaceInvaders.aspx" target="_blank"&gt;http://www.michaelckennedy.net/blog/2009/10/28/TDDInvadesSpaceInvaders.aspx&lt;/a&gt;] 
&lt;br /&gt;
&lt;hr size="1" /&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3&gt;Avoiding 5 Common Pitfalls in Unit Testing
&lt;/h3&gt;
by &lt;a href="http://blog.approvaltests.com/" target="_blank"&gt;Llewellyn Falco&lt;/a&gt; and &lt;a href="http://www.michaelckennedy.net/" target="_blank"&gt;Michael
Kennedy&lt;/a&gt; 
&lt;br /&gt;
&lt;br /&gt;
When I started out with unit tests, I was enthralled with the promise of ease and
security that they would bring to my projects. In practice, however, the theory of
sustainable software through unit tests started to break down. This difficulty continued
to build up, until I finally threw my head back in anger and declared that 
&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3&gt;&amp;quot;Unit Tests have become more trouble than they are worth.&amp;quot;
&lt;/h3&gt;
So we stopped. Not all once, but over the months our unit tests died a quiet death.
When tests would stop working, we just ignored them. When new features were reported,
they were developed without unit testing. At first, it seemed great. We were able
to move without the baggage of maintaining the old tests! But soon all the original
problems of having a system without tests came back to us. Things keep breaking, deadlines
were increasingly pushed back. Releases came with an extraordinary amount of stress,
late nights &amp;amp; weekends. The final straw came when we were forced to rush out an
immediate update, and ended up taking down the company for 2 days straight. Our new
motto became: 
&lt;br /&gt;
&lt;h3&gt;&amp;quot;Unit Testing: you're damned if you do, you're damned if you don't.&amp;quot;
&lt;/h3&gt;
In the end, we decided that despite the hardship caused by maintaining unit tests,
it just wasn't feasible to operate without them. So we started down the road to re-incorporate
testing into our software development process. As the months went by, however, we
discovered that the hardships we remembered had not returned. Looking back, we realized
that we had made many mistakes the first time around. The second time around we were
smarter. So you, too, can enjoy the benefits of unit tests here are the 5 major pitfalls
we encountered the first time around, and how you can avoid them. 
&lt;br /&gt;
&lt;h2&gt;Pitfall #1: Tests are hard to maintain.
&lt;/h2&gt;
Because tests were only there to service and support the production code, they became
second class citizens. We would spend time carefully choosing method names, refactoring
our code to keep our classes and methods small, and so on. But we never applied these
same principles to our test code. 
&lt;br /&gt;
&lt;br /&gt;
As a side-effect of adding back the old tests, we reviewed and cleaned them up with
the same level of scrutiny we gave to our &amp;quot;real&amp;quot; code. Suddenly the tests
were easier to maintain. While this should not be a surprise to anyone, it wasn't
util this moment that we realized why they had been so hard to maintain in the first
place: 
&lt;h3&gt;Our tests were hard to maintain because we weren't maintaining them.
&lt;/h3&gt;
Solution: Going forward, we expect the same quality of code (or higher) in the unit
tests as we do for our production code. That means 
&lt;table width="500"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;ul&gt;
&lt;li&gt;
We remove duplication 
&lt;/li&gt;
&lt;li&gt;
We carefully consider method names 
&lt;/li&gt;
&lt;li&gt;
We create convenience functions for testing features 
&lt;/li&gt;
&lt;li&gt;
We keep our methods short 
&lt;/li&gt;
&lt;li&gt;
We code-review our unit tests 
&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Pitfall #2: Tests are lot of work to write.
&lt;/h2&gt;
We found that in order to test even simple things we would have to write lots of code
to setup and execute the scenario. Even something simple like &amp;quot;create a new user,
and receive welcome email&amp;quot; would turn into 40-50 lines of step by step instructions. 
&lt;br /&gt;
&lt;br /&gt;
Not only was this a pain to write the 1st time, it became a nightmare to maintain.
Little changes would mean re-reading those functions to detect if the test was failing
because we broke something, or simply because we had changed something. Once that
was discovered, we would then have to update the now out of sync test code. 
&lt;br /&gt;
&lt;br /&gt;
The solution we actually found may surprise you. We found that writing out our tests
in English and then translating each line into 1 line of code naturally created the
appropriate levels of abstraction and readability. 
&lt;br /&gt;
&lt;br /&gt;
For example, let's consider testing the following scenario: 
&lt;br /&gt;
&lt;br /&gt;
Who are you receiving the most email from? 
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;
Create you - the user 
&lt;/li&gt;
&lt;li&gt;
Mike sends you 3 emails 
&lt;/li&gt;
&lt;li&gt;
Mary sends you 4 emails 
&lt;/li&gt;
&lt;li&gt;
Joan sends you 2 emails 
&lt;/li&gt;
&lt;li&gt;
Verify your greatest &amp;quot;emailer&amp;quot; is Mary 
&lt;/li&gt;
&lt;/ol&gt;
This will naturally lead us to write the following test method and helper method: 
&lt;br /&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class="brush: csharp"&gt;[TestFixture]
public class AccountTests
{
    private MockMailServer mockMailServer = new MockMailServer();

    [Test]
    public void WhoAreYouReceivingTheMostEmailFrom()
    {
        User you = User.CreateNew( &amp;quot;you&amp;quot; );
        User mike = SendEmailHelper( CreateUser( &amp;quot;mike&amp;quot; ), you, 3 );
        User mary = SendEmailHelper( CreateUser( &amp;quot;mary&amp;quot; ), you, 4 );
        User joan = SendEmailHelper( CreateUser( &amp;quot;joan&amp;quot; ), you, 2 );

        Assert.AreEqual( mary, you.GetGreatestEmailer() );
    }

    private User SendEmailHelper(User from, User to, int quantity)
    {
        for ( int i = 0; i &amp;lt; quantity; i++ )
        {
            EMail mail = new EMail()
            {
                To = to, 
                From = from, 
                Body = &amp;quot;Sample&amp;quot;,
                Subject = &amp;quot;test&amp;quot;
            };

            mail.SetFormat( Formats.Html );
            mockMailServer.Send( mail );
        }
        return from;
     }&lt;/pre&gt;
&lt;br /&gt;
Notice that to a programmer, the lines of code in the &lt;i&gt;&lt;b&gt;WhoAreYouReceivingTheMostEmailFrom&lt;/b&gt;&lt;/i&gt;&lt;b&gt;&lt;/b&gt; test
are as easy to read as the lines of English were. We were naturally motivated to create
the &amp;quot;SendEmailHelper&amp;quot; function because that was required by one-to-one correlation
between the lines of English and the lines of test code. However, without that helper,
our test would have become an unreadable rat's nest. This also naturally removes some
duplication, increases maintainability, and allows for some reuse of the test convenience
functions. This won't be the only test that requires us to send email; for example,
we may want to test that we can find out to whom you sent the most email. 
&lt;br /&gt;
&lt;br /&gt;
Let's compare this to how our tests would look if we had just hacked out the scenario: 
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;[Test]
  public void WhoAreYouReceivingTheMostEmailFrom()
  {
      User you = User.CreateNew(&amp;quot;you&amp;quot;);
      User mike = CreateUser(&amp;quot;mike&amp;quot;);
      for (int i = 0; i &amp;lt; 3; i++)
      {
          EMail mail = new EMail{To = you,From = mike, Body = &amp;quot;Sample&amp;quot;, Subject = &amp;quot;test&amp;quot;};
          mail.SetFormat(Formats.Html);
          mockMailServer.Send(mail);
      }
      
      User mary = CreateUser(&amp;quot;mary&amp;quot;);
      for (int i = 0; i &amp;lt; 4; i++)
      {
          EMail mail1 = new EMail{To = you,From = mary,Body = &amp;quot;Sample&amp;quot;,Subject = &amp;quot;test&amp;quot;};
          mail1.SetFormat(Formats.Html);
          mockMailServer.Send(mail1);
      }
          
      User joan = CreateUser(&amp;quot;joan&amp;quot;);
      for (int i = 0; i &amp;lt; 6; i++)
      {
          EMail mail2 = new EMail {To = you, From = joan,Body = &amp;quot;Sample&amp;quot;,Subject = &amp;quot;test&amp;quot;};
          mail2.SetFormat(Formats.Html);
          mockMailServer.Send(mail2);
      }
      
      Assert.AreEqual(mary, you.GetGreatestEmailer());
      }&lt;/pre&gt;
&lt;br /&gt;
Because we wrote the first version in English it's also easier to detect a mistake.
You may have noticed that the second example had a typo at line 31, making Joan the
biggest emailer. In general long methods have the disadvantage of obscuring intent.
Unfortunately the 'follow a script' aspect of testing lends itself to writing long
methods. By writing the tests in English and then doing a 1-to-1 conversion to code
we can counter this vulnerability. 
&lt;br /&gt;
&lt;h3&gt;Write the tests in English before you code them.
&lt;/h3&gt;
&lt;h2&gt;Pitfall #3: Adding a new feature breaks a lot of tests that I then need to adjust.
&lt;/h2&gt;
I always dreaded adding new features because I knew it meant the existing tests were
going to complain about the changes. It seemed like the tests themselves were resisting
change to my system, rather than supporting it. As I made changes and the tests broke,
I was always trying to figure out if those changes were &amp;quot;expected&amp;quot; because
of the new feature, or unintended bugs I had introduced into my software. 
&lt;br /&gt;
&lt;br /&gt;
Nowadays, we always &lt;b&gt;prep the system for the new feature&lt;/b&gt;. This allows us to
isolate 'expected' changes from unintended bugs. Furthermore, once we have finished
prepping for the new feature, we find it extremely easy to actually add that new feature.
Best of all, if the unit test breaks now, we know it's because of unexpected side
effects of our changes. 
&lt;br /&gt;
&lt;br /&gt;
This 'prepping' period falls under the title of 'refactoring' and requires the simple
rule that during this stage you do not change the behavior, only the implementation.
This sounds straight forward and simple, but in practice it requires a great deal
of discipline. 
&lt;br /&gt;
&lt;br /&gt;
Personally, I still find it a challenge to &lt;b&gt;NOT&lt;/b&gt; fix a bug discovered during
refactoring. I have to force myself to leave it alone and wait until I have finished
refactoring before changing (Fixing) this behavior, but this discpline has paid off
many, many times. 
&lt;br /&gt;
&lt;br /&gt;
During this period, the support provided by your unit test suite really shines. Those
tests allow me to rework my code with confidence. Afterwards the architecture in place
has been custom designed to support the addition of this particular new feature, thus
making its implementation quite straightforward. In our experience the 'prepping'
work tends to actually take more time than we spend adding the actual feature itself,
but the total time to implement is much less. 
&lt;br /&gt;
&lt;br /&gt;
By spliting the work into two phases, we can emphasize the fact that the unit tests
are supporting the &lt;i&gt;existing system&lt;/i&gt; allowing its architecture to evolve so that
extending it does not become increasingly difficult. 
&lt;br /&gt;
&lt;br /&gt;
Before I would ask myself &amp;quot;How can I add this new feature?&amp;quot; Now I ask &amp;quot;How
can I make it so this new feature will be easy to add?&amp;quot; 
&lt;br /&gt;
&lt;h3&gt;Prep the system for the new feature first.
&lt;/h3&gt;
&lt;h2&gt;Pitfall #4: When I change something a whole bunch of tests break even though I
haven't broken the system.
&lt;/h2&gt;
There are many ways to solve the same problem. In the past, we tended to test a specific
implementation of a solution instead of testing that we &lt;b&gt;had&lt;/b&gt; a solution. Because
we were focused on the specifics of implementation, changes to our solutions kept
breaking our tests, even though we still had a valid solution. Moreover, because the
tests were closely tied to implementation, rediscovering the intent and separating
it in the tests became cumbersome. As we became more proficient at writing tests in
English, we were able to create unit tests that described the expected behavior. This
conveys a higher level of intent, and made the tests much less brittle. 
&lt;br /&gt;
&lt;br /&gt;
Let's look at an example: 
&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;[Test]
  public void TestGatewayCallSuccessful()
  {
      var gateway = new Gateway {Mask = &amp;quot;ExampleCode.*&amp;quot;};
      var enviroment = new Dictionary&lt;string , String&gt;
(); enviroment.Add(&amp;quot;path&amp;quot;, &amp;quot;ExampleCode.HelloWorld&amp;quot;); string result
= gateway.ExecuteRequest(enviroment); Assert.IsTrue(result.Contains(&amp;quot;Hello World&amp;quot;));
} [Test] public void TestGatewayBlocksInvalidMasks() { Assert.IsFalse(Gateway.IsValidForMask(
&amp;quot;Example.*&amp;quot;, &amp;quot;ExampleCode.HelloWorld&amp;quot;)); Assert.IsFalse(Gateway.IsValidForMask(
&amp;quot;ExampleCode.*.Extras.*&amp;quot;, &amp;quot;ExampleCode.HelloWorld&amp;quot;)); Assert.IsTrue(Gateway.IsValidForMask(
&amp;quot;ExampleCode.*&amp;quot;, &amp;quot;ExampleCode.HelloWorld&amp;quot;)); }
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
In this example, we wrote our second test &lt;b&gt;&lt;i&gt;TestGatewayBlocksInvalidMasks&lt;/i&gt;&lt;/b&gt; so
we could easily test a few examples to make sure our implementation was correct. In
doing so we exposed a method &lt;i&gt;&lt;b&gt;IsValidForMask&lt;/b&gt;&lt;/i&gt;, which was an implementation
detail and was only made public in order to make testing easy and intentional. We
did this because actually executing something to get the failure was much more involved
as evidenced by the first test (&lt;i&gt;&lt;b&gt;TestGatewayCallSuccessful&lt;/b&gt;&lt;/i&gt;). 
&lt;br /&gt;
&lt;br /&gt;
Let's take a look at the specific solution we've come up with: 
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;public class Gateway : IRunner
  {
      public string Mask { get; set; }
      
      public String ExecuteRequest(Dictionary&lt;string , string&gt;
environment) { string path = environment[&amp;quot;path&amp;quot;]; AssertValidClass(path);
IRunner instance = (IRunner)Activator.CreateInstance(Type.GetType(path)); return instance.ExecuteRequest(environment);
} private void AssertValidClass(string path) { if (!IsValidForMask(Mask, path)) {
throw new Exception(String.Format( &amp;quot;Invalid Path '{0}' for Mask '{1}'&amp;quot;,
path, Mask)); } } internal static bool IsValidForMask(String mask, String path) {
mask = mask.Replace(&amp;quot;.&amp;quot;, &amp;quot;\\.&amp;quot;).Replace(&amp;quot;*&amp;quot;, &amp;quot;.*&amp;quot;);
Regex regex = new Regex(mask); return regex.IsMatch(path); } }
&lt;/pre&gt;
&lt;br /&gt;
As we can see, even though we are only creating this gateway once each time a call
to &lt;i&gt;&lt;b&gt;ExecuteRequest&lt;/b&gt;&lt;/i&gt; is made we have to recreate the regex expression (line
31 &amp;amp; 32). It would be nice to do this just once. Let's take a look at a more efficient
solution: 
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;public class Gateway : IRunner
  {
      private string mask;
      private Regex regex;
      
      public string Mask
      {
         get { return mask; }
         set
         {
            mask = value;
            regex = new Regex( mask.Replace( &amp;quot;.&amp;quot;, &amp;quot;\\.&amp;quot; ).Replace( &amp;quot;*&amp;quot;, &amp;quot;.*&amp;quot; ) );
         }
      }
      
      public String ExecuteRequest(Dictionary&lt;string , string&gt;
environment) { string path = environment[&amp;quot;path&amp;quot;]; AssertValidClass(path);
IRunner instance = (IRunner) Activator.CreateInstance(Type.GetType(path)); return
instance.ExecuteRequest(environment); } private void AssertValidClass(string path)
{ if (!regex.IsMatch(path)) { throw new Exception(String.Format(&amp;quot;Invalid Path
'{0}' for Mask '{1}'&amp;quot;, path, Mask)); } } }
&lt;/pre&gt;
&lt;br /&gt;
&lt;br /&gt;
Unfortunately this refactoring breaks the first set of tests. Notice that the function
we are calling no longer even exists. However, let's look at what happens if we write
our tests for the behavior rather than the implementation: 
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="brush: csharp"&gt;[TestFixture]
  public class GatewayBehaviorTests
  {
     [Test]
     private void TestGatewayCallSuccessful()
     {
         string result = Run(&amp;quot;ExampleCode.*&amp;quot;, &amp;quot;ExampleCode.HelloWorld&amp;quot;);
         Assert.IsTrue(result.Contains(&amp;quot;Hello World&amp;quot;));
      }
      
      [Test]
      public void TestGatewayBlocksInvalidMasks()
      {
          AssertValidForMask(false, &amp;quot;Example.*&amp;quot;, &amp;quot;ExampleCode.HelloWorld&amp;quot;);
          AssertValidForMask(false, &amp;quot;ExampleCode.*.Extras.*&amp;quot;, &amp;quot;ExampleCode.HelloWorld&amp;quot;);
          AssertValidForMask(true, &amp;quot;ExampleCode.*&amp;quot;, &amp;quot;ExampleCode.HelloWorld&amp;quot;);
      }
      
      private static String Run(string mask, string path)
      {
          var gateway = new OptimizedGateway {Mask = mask};
          var enviroment = new Dictionary&lt;string , string&gt;
(); enviroment.Add(&amp;quot;path&amp;quot;, path); string result = gateway.ExecuteRequest(enviroment);
return result; } private void AssertValidForMask( bool exceptionExpected, string mask,
string path) { Exception found = null; try { Run(mask, path); } catch (Exception ex)
{ found = ex; } Assert.AreEqual(exceptionExpected, found == null); } }
&lt;/pre&gt;
&lt;br /&gt;
There are a few things to notice now: 
&lt;table width="500"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;ul&gt;
&lt;li&gt;
This test not only works for the new code, but the old code as well. This is because
the behavior has not changed, just the implementation. 
&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;
We have not sacrificed readability or clarity of intent. In fact the first test &lt;i&gt;&lt;b&gt;TestGatewayCallSuccessful&lt;/b&gt;&lt;/i&gt; has
actually gained readability. 
&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;
There is the introduction of helper methods in the unit test. We find that this is
a side effect of writing tests for readability and intention. 
&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
In the end, we realized there is a particular code smell for this problem. 
&lt;br /&gt;
&lt;h3&gt;If a different implementation of a solution requires different tests, you are
testing to the wrong level.
&lt;/h3&gt;
&lt;h2&gt;Pitfall #5: There are just too many possibilities to test
&lt;/h2&gt;
When we first began unit testing, we felt that we had to test as many inputs as possible
because we believed the purpose of the unit tests was to ensure complete quality of
our code. What we have learned is that the world is not black and white, and neither
is testing. It is not the case that we either have verified code or unverified code.
There are levels of protection. In fact there is a level at which you get diminishing
returns from new inputs and, surprisingly, that number is often very small. 
&lt;br /&gt;
&lt;br /&gt;
For example: Imagine the following scenarios : 
&lt;br /&gt;
&lt;br /&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td class="scenario" colspan="2"&gt;
Scenario 1 
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
You have a method 
&lt;br /&gt;
&lt;pre&gt;public int doSomething(int a, int b) {/*...*/})&lt;/pre&gt;
Does this method work? 
&lt;br /&gt;
Will it blow up if I run it? 
&lt;br /&gt;
On a scale of 1-10 what is your confidence level? 
&lt;br /&gt;
&lt;/td&gt;
&lt;td&gt;
Confidence Level 2: In our case, our confidence started out at 2. All we know is that
it compiled. &lt;i&gt;Any number of things could be wrong.&lt;/i&gt;. 
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class="scenario" colspan="2"&gt;
Scenario 2 
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
Now, assume you have an invocation of the method &lt;pre&gt;doSomething(2,3);&lt;/pre&gt;
When you run this, it does not crash although you have no way to check its result. 
&lt;br /&gt;
What's your confidence level now? 
&lt;/td&gt;
&lt;td&gt;
Confidence Level 6:&amp;#160; As soon as it's been executed, our confidence jumps up to
a 6. We know that most bugs come from incorrect wiring, or null pointers, and so on.
Now we know it's not blowing up, but still don't really know that it's working 
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td class="scenario" colspan="2"&gt;
Scenario 3 
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
Now imagine that you have a test &lt;pre&gt;assertEquals(8, doSomething(2,3));&lt;/pre&gt;
This test passes. 
&lt;br /&gt;
What's your confidence level now? 
&lt;br /&gt;
&lt;/td&gt;
&lt;td&gt;
Confidence Level 8:&amp;#160; Just a single confirmation pulls us all the way up to a
confidence level of 8. Notice that we are still just at 1 test case. A few more and
we'll be in the 9's, but how many more cases would you need to say with absolute confidence
that this works? (hint: 2^32 * 2^32). 
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 
&lt;br /&gt;
Tests are like seatbelts: just because they won't guarantee your survival in all crashes,
it doesn't mean you shouldn't wear them. Take the extreme case of a motorcycle helmet.
You are only protecting a small part of your body, but you are significantly improving
the odds of survival if something goes wrong. 
&lt;br /&gt;
&lt;br /&gt;
A general rule of thumb for the number of cases to tests is &amp;quot;&lt;font size="+2"&gt;3&lt;/font&gt; is
a big number&amp;quot;. 
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;
Test the happy path 
&lt;/li&gt;
&lt;li&gt;
Test an edge case 
&lt;/li&gt;
&lt;li&gt;
Test an error case, if you have one 
&lt;/li&gt;
&lt;/ol&gt;
Start with the happy path. If you still are worried, try an edge case. Wait until
a problem presents itself before you test further. 
&lt;br /&gt;
&lt;h3&gt;Spend your time where it counts.
&lt;/h3&gt;
&lt;br /&gt;
&lt;/div&gt;
&lt;img width="0" height="0" src="http://www.michaelckennedy.net/blog/aggbug.ashx?id=b337cd7c-528d-4e47-a3c9-736c45c35d6d" /&gt;
&lt;br /&gt;
&lt;hr /&gt;All content copyright Michael C. Kennedy. All information, source code, and especially tools are provided as is and on a "use at your own risk" basis.&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=bOqt0E60kiM:kg2MYv8xNkg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=bOqt0E60kiM:kg2MYv8xNkg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=bOqt0E60kiM:kg2MYv8xNkg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=bOqt0E60kiM:kg2MYv8xNkg:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=bOqt0E60kiM:kg2MYv8xNkg:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=bOqt0E60kiM:kg2MYv8xNkg:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=bOqt0E60kiM:kg2MYv8xNkg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=bOqt0E60kiM:kg2MYv8xNkg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=bOqt0E60kiM:kg2MYv8xNkg:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=bOqt0E60kiM:kg2MYv8xNkg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=bOqt0E60kiM:kg2MYv8xNkg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MichaelCKennedysWeblog/~4/bOqt0E60kiM" height="1" width="1"/&gt;</description>
      <comments>http://www.michaelckennedy.net/blog/CommentView,guid,b337cd7c-528d-4e47-a3c9-736c45c35d6d.aspx</comments>
      <category>Articles</category>
      <category>DevelopMentor</category>
      <category>Unit Testing</category>
    <feedburner:origLink>http://www.michaelckennedy.net/blog/2009/08/08/ArticleAvoiding5CommonPitfallsInUnitTesting.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.michaelckennedy.net/blog/Trackback.aspx?guid=7b884725-09f5-421e-ab4e-4f76c9d5f761</trackback:ping>
      <pingback:server>http://www.michaelckennedy.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.michaelckennedy.net/blog/PermaLink,guid,7b884725-09f5-421e-ab4e-4f76c9d5f761.aspx</pingback:target>
      <dc:creator>Michael Kennedy</dc:creator>
      <wfw:comment>http://www.michaelckennedy.net/blog/CommentView,guid,7b884725-09f5-421e-ab4e-4f76c9d5f761.aspx</wfw:comment>
      <wfw:commentRss>http://www.michaelckennedy.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=7b884725-09f5-421e-ab4e-4f76c9d5f761</wfw:commentRss>
      
      <title>Article: Building a Twitter Application in .NET</title>
      <guid isPermaLink="false">http://www.michaelckennedy.net/blog/PermaLink,guid,7b884725-09f5-421e-ab4e-4f76c9d5f761.aspx</guid>
      <link>http://feedproxy.google.com/~r/MichaelCKennedysWeblog/~3/IlQU52TO5tg/ArticleBuildingATwitterApplicationInNET.aspx</link>
      <pubDate>Fri, 07 Aug 2009 20:22:02 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
I recently wrote an article for &lt;a href="http://www.develop.com" target="_blank"&gt;DevelopMentor&lt;/a&gt;'s&#xD;
Developments newsletter entitled &lt;u&gt;&lt;i&gt; Building a Twitter Application in .NET&lt;/i&gt;&lt;/u&gt;.&lt;br&gt;&lt;br&gt;&#xD;
You can read it at the DevelopMentor website:&lt;br&gt;&lt;br&gt;&lt;a href="http://www.develop.com/twitternetapps" target="_blank"&gt;http://www.develop.com/twitternetapps&lt;/a&gt;&lt;br&gt;&lt;br&gt;&#xD;
I've republished here for my readers. Enjoy! &#xD;
&lt;/p&gt;&#xD;
        &lt;hr size="1"&gt;&lt;/hr&gt;&#xD;
        &lt;h3&gt;&#xD;
Building a Twitter Application in .NET&#xD;
&lt;/h3&gt;&#xD;
by Michael Kennedy (&lt;a href="http://twitter.com/mkennedy" target="_blank"&gt;@mkennedy&lt;/a&gt;)&lt;br&gt;&lt;a href="http://www.michaelckennedy.net" target="_blank"&gt;http://www.michaelckennedy.net&lt;/a&gt;&lt;br&gt;&lt;p&gt;&#xD;
Twitter has become one of the web's hottest properties. It is a central part of mainstream&#xD;
news programs such as CNN's Anderson Cooper 360, congressional debates, and talk shows.&#xD;
In fact, it grew at a rate of 1400% this past year [&lt;a href="http://bit.ly/jG9BG" target="_blank"&gt;bit.ly/jG9BG&lt;/a&gt;].&lt;br&gt;&lt;/p&gt;&lt;p&gt;&#xD;
If your company wants to interact with your customers in a modern and engaging experience,&#xD;
you need to be on Twitter. In fact, if you have customers that really like or dislike&#xD;
you, they are probably talking about you on Twitter. You should be part of that conversation.&lt;br&gt;&lt;/p&gt;&lt;p&gt;&#xD;
In this article, we will explore how to build a rich interactive experience on Twitter&#xD;
that goes beyond just creating a new Twitter account. We will build a .NET application&#xD;
that uses the Twitter API (a free service) alongside other cool technologies such&#xD;
as the WCF REST Starter Kit [&lt;a href="http://bit.ly/v8mBb" target="_blank"&gt;http://bit.ly/v8mBb&lt;/a&gt;]&#xD;
and LINQ to fully leverage the Twitter experience.&lt;br&gt;&lt;/p&gt;&lt;p&gt;&#xD;
Whether you want to build a community around your brand or you want to build the next&#xD;
real-time, social community website like .NET Developer Buzz [&lt;a href="http://dotnet.ubbuzz.com/" target="_blank"&gt;http://dotnet.ubbuzz.com/&lt;/a&gt;],&#xD;
this article will cover the technologies required to get the job done.&#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
If you want to download the sample application to follow along, you can get it here:&lt;br&gt;&lt;a href="http://www.michaelckennedy.com/Samples/SampleStatusUpdater.zip" target="_blank"&gt;http://www.michaelckennedy.com/Samples/SampleStatusUpdater.zip&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&#xD;
While you're at it, be sure to follow DevelopMentor on Twitter:&lt;br&gt;&lt;a href="http://twitter.com/dm_the_company" target="_blank"&gt;http://twitter.com/dm_the_company&lt;/a&gt;&lt;br&gt;&lt;/p&gt;&lt;h3&gt;&#xD;
Let's Start Small&#xD;
&lt;/h3&gt;&lt;p&gt;&#xD;
I will show you how to fully leverage the Twitter API, but many tasks can be accomplished&#xD;
using simpler tools and you may be better starting there. Let's look at a few things&#xD;
that we can do without the Twitter API.&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Case 1.&lt;/b&gt; You want to display your latest Twitter messages on your website.&lt;br&gt;&lt;/p&gt;&lt;p&gt;&#xD;
Your tweets[1], as they're called, can be consumed as a simple RSS feed. So you may&#xD;
want to simply pull this feed into your website rather than digging into the Twitter&#xD;
API and consuming custom XML or JSON formats. An example of consuming Twitter in this&#xD;
fashion can be found on my website's front page [&lt;a href="http://www.michaelckennedy.net/" target="_blank"&gt;http://www.michaelckennedy.net/&lt;/a&gt;].&#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
To get your RSS feed, just visit your profile page and get the RSS tweet link, e.g.&#xD;
"RSS feed of mkennedy's tweets" [&lt;a href="http://bit.ly/guhZU" target="_blank"&gt;http://bit.ly/guhZU&lt;/a&gt;]&#xD;
&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;[1] Tweet - these are what the individual messages sent on Twitter are called.&#xD;
If the name sounds weird, I'm sure you'll get used to it. Remember that there was&#xD;
a time when Google was just a noun.&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;b&gt;Case 2.&lt;/b&gt; You want to watch and manage multiple accounts at the same time.&#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
Most Twitter clients only support a single user. But there are a couple of good tools&#xD;
that allow you to manage multiple accounts. My current favorite is one called bDule&#xD;
and you can get for free at &lt;a href="http://www.sobees.com/bdule" target="_blank"&gt; http://www.sobees.com/bdule&lt;/a&gt;.&#xD;
&lt;/p&gt;&lt;h3&gt;&#xD;
Beyond the Small&#xD;
&lt;/h3&gt;&lt;p&gt;&#xD;
There are times when you want to do more than simply syndicate your Twitter stream.&#xD;
Let me give you an example. At DevelopMentor, we have had many instructors on Twitter&#xD;
talking about their own interests. But we didn't have a corporate Twitter presence.&#xD;
We decided to create our corporate presence by pulling all our instructors individual&#xD;
tweets and rebroadcasting them from our DevelopMentor Twitter account: &lt;a href="http://twitter.com/dm_the_company" target="_blank"&gt; @dm_the_company&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&#xD;
We wanted to keep a sense of the original instructor who wrote the message, so we&#xD;
append on an attribution. For example:&#xD;
&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;"Software Transactional Memory is released! (via @mkennedy)&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&#xD;
and we wanted to do this in a flexible way. In short, we needed more functionality&#xD;
than Twitter provides. &#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
There are actually three services that do this sort of thing and they looked promising. &#xD;
&lt;br&gt;&lt;br&gt;&lt;a href="http://www.connecttweet.com/" target="_blank"&gt;http://www.connecttweet.com/&lt;/a&gt;&lt;br&gt;&lt;a href="http://www.grouptweet.com/" target="_blank"&gt;http://www.grouptweet.com/&lt;/a&gt;&lt;br&gt;&lt;a href="http://cotweet.com/" target="_blank"&gt;http://cotweet.com/&lt;/a&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;&#xD;
But in the end, nothing completely matched our requirements. So we decided to write&#xD;
our own application to publish everyone's tweets under the DevelopMentor banner. There&#xD;
are few simple steps involved as well as a lot of details we won't go into yet.&#xD;
&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&#xD;
Take a list of Twitter accounts and download everyone's statuses.&lt;/li&gt;&lt;li&gt;&#xD;
Determine which messages we haven't seen before.&lt;/li&gt;&lt;li&gt;&#xD;
Publish these new statuses under our corporate account.&lt;br&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&#xD;
We can actually implement a simplistic version of this by continuing to use the public&#xD;
RSS feeds of the individual accounts in conjunction with a very handy Twitter API&#xD;
wrapper called TwitterooCore which you can find at &lt;a href="http://rareedge.com/twitteroo/blog/" target="_blank"&gt;http://rareedge.com/twitteroo/blog/&lt;/a&gt;.&#xD;
&lt;/p&gt;&lt;h3&gt;&#xD;
The Twitter API&#xD;
&lt;/h3&gt;&lt;p&gt;&#xD;
In practice, there is simply data missing from the RSS feed that we require as well&#xD;
as features missing from the Twitteroo Core that move us deeper into the Twitter API.&#xD;
One thing you may well miss is the ability to tie together conversations. For example&#xD;
if Bob says "hello" and Jerry says in reply "@bob Back at you!" Twitter tracks that&#xD;
Jerry replied to Bob and publishes this link in the stream. To get access to these&#xD;
types of features and many other optimizations, you'll need to use the REST-based&#xD;
Twitter API.&#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
The Twitter API is documented at &lt;a href="http://apiwiki.Twitter.com/" target="_blank"&gt; http://apiwiki.Twitter.com/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&#xD;
There you can do things like get the users tweets, if their tweets are public, by&#xD;
requesting:&#xD;
&lt;/p&gt;&lt;p&gt;&lt;a href="http://twitter.com/statuses/user_timeline.xml?screen_name=mkennedy" target="_blank" style="margin-left: 40px;"&gt;http://twitter.com/statuses/user_timeline.xml?screen_name=mkennedy&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&#xD;
What you get back to dependent on the requested format. Here we're asking for XML&#xD;
(user_timeline.xml) but we can also get JSON, RSS, or ATOM.&#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
Similarly, we can update our status by making a POST request to:&#xD;
&lt;/p&gt;&lt;p&gt;&lt;a href="http://twitter.com/statuses/update.xml" target="_blank" style="margin-left: 40px;"&gt; http://twitter.com/statuses/update.xml&lt;/a&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;&#xD;
Here again we have the four possible formats: XML, JSON, RSS, ATOM. However this time&#xD;
we're using a form post for the request to update the user status which is then in-turn&#xD;
returned as XML.&#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
Great, we have this cool REST API based on loosely-typed GETs and POSTs. Should we&#xD;
program against it using fundamental .NET types such as WebRequest, WebClient, and&#xD;
similar classes? We could. But WebRequest is &lt;span class="style2"&gt;so&lt;/span&gt; .NET 1.0&#xD;
(circa 2001). There is a much newer API on the verge of release from Microsoft: The&#xD;
REST Starter Kit [&lt;a href="http://bit.ly/1IF3Ji" target="_blank"&gt;http://bit.ly/1IF3Ji&lt;/a&gt;].&#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
While this toolkit is generally geared towards building to RESTful WCF services, there's&#xD;
also a great set of classes for building REST clients. We will use these classes to&#xD;
write our application. Let's take a look at how we can use the Twitter API to write&#xD;
are simple application.&#xD;
&lt;/p&gt;&lt;h3&gt;&#xD;
The REST Starter Kit&#xD;
&lt;/h3&gt;&lt;h4&gt;&#xD;
Part 1 - Getting the users of tweets.&#xD;
&lt;/h4&gt;&lt;p&gt;&#xD;
We need to download the users messages as XML and convert them to .NET objects that&#xD;
we can consume our application. This is really straightforward because the REST Starter&#xD;
Kit as a cool feature to Visual Studio: "Paste XML as Types". This feature will take&#xD;
an XML file and auto-generate types based on the inferred XML schema. In our case,&#xD;
the XML file we will use is returned from the user timeline.&lt;br&gt;&lt;br&gt;&lt;a href="http://twitter.com/statuses/user_timeline.xml?screen_name=mkennedy" target="_blank"&gt; http://twitter.com/statuses/user_timeline.xml?screen_name=mkennedy&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&#xD;
Open a link in a web browser, choose view source, and copy some XML. Then go to Visual&#xD;
Studio, choose edit, Paste XML as Types. Of course you must have the REST Starter&#xD;
Kit installed for this to work.[2]&#xD;
&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;[2] In my experience I ran into some errors deserializing the response from Twitter.&#xD;
See the &lt;span class="style2"&gt;The Real World Intrudes&lt;/span&gt;&lt;/i&gt; section at the end&#xD;
of the article if you run into difficulties.&#xD;
&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&#xD;
After generating our status related types, we can use the HttpClient class to download&#xD;
the statuses. &#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
Listing 1.&#xD;
&lt;/p&gt;&lt;pre class="brush: csharp"&gt;private static void GetStatuses(IEnumerable&lt;string&gt;&#xD;
userNames) { XmlSerializer serl = new XmlSerializer(typeof (statuses)); serl.UnknownElement&#xD;
+= delegate { }; foreach (string name in userNames) { string url = string.Format(&#xD;
"http://twitter.com/statuses/user_timeline.xml?screen_name={0}", name); HttpClient&#xD;
client = new HttpClient(url); HttpResponseMessage response = client.Get(); response.EnsureStatusIsSuccessful();&#xD;
string contents = response.Content.ReadAsString(); Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(contents));&#xD;
statuses userStatuses = (statuses) serl.Deserialize(stream); if ( userStatuses.status.Length&#xD;
&amp;gt; 0 ) { Console.WriteLine( "@{0}'s latest tweet: {1}", name,userStatuses.status[0].text&#xD;
); } Console.WriteLine(); } }&#xD;
&lt;/string&gt;&lt;/pre&gt;&lt;!--&lt;img src="listing1.png" /&gt;&lt;br /&gt;--&gt;&lt;p&gt;&#xD;
There are two main things happening in this code. We're using the HttpClient class&#xD;
to download the web content associated with the given user's timeline. Then we're&#xD;
using the XmlSerializer in conjunction with the auto-generated XML-serializable types&#xD;
from the "Paste XML as Types" command. That's all there is to it. The REST Starter&#xD;
Kit does most of the work for us.&#xD;
&lt;/p&gt;&lt;h3&gt;&#xD;
Part 2 - Checking for New Messages&#xD;
&lt;/h3&gt;&lt;p&gt;&#xD;
Now that we have all the statuses, we need to find the ones that we haven't broadcasted&#xD;
from our main account and send them along to step 3. We won't go into detail on how&#xD;
to track that. But you can imagine a simple database that facilitates a LINQ to SQL&#xD;
query like this:&#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
Listing 2.&#xD;
&lt;/p&gt;&lt;pre class="brush: csharp"&gt;public StatusUpdate[] FindRebroadcastableStatuses(StatusUpdate[] updates)&#xD;
{&#xD;
    return&#xD;
        (from up in updates&#xD;
         let neverPosted = up.User.LastPostBroadcasted == null&#xD;
         let afterPostDate = up.Time &amp;gt; up.User.LastPostBroadcasted&#xD;
         where neverPosted || afterPostDate&#xD;
         select up).ToArray();&#xD;
}&lt;/pre&gt;&lt;!--&lt;img src="listing2.png" /&gt;&lt;br /&gt;--&gt;&lt;h3&gt;&#xD;
Part 3 - Publishing the Statuses&#xD;
&lt;/h3&gt;&lt;p&gt;&#xD;
Now that we've gathered the statuses of our various users, it's time to rebroadcast&#xD;
them to our community. We're going back to the Twitter API to update our status. Again&#xD;
will use the HttpClient class and following the RESTful principle of using POST to&#xD;
add new items to a given URI. We will do an HTTP POST to our status to add a new message&#xD;
to the account.&#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
Listing 3.&#xD;
&lt;/p&gt;&lt;pre class="brush: csharp"&gt;private void UpdateStatus(string newStatus, long? replyToId)&#xD;
{&#xD;
    string url = "https://twitter.com/statuses/update.xml";&#xD;
&#xD;
    HttpClient client = new HttpClient( url );&#xD;
    client.TransportSettings.Credentials = &#xD;
        new NetworkCredential( twitterUser, password );&#xD;
&#xD;
    HttpUrlEncodedForm form = new HttpUrlEncodedForm();&#xD;
    form.Add( "status", newStatus );&#xD;
    if ( replyToId != null )&#xD;
    {&#xD;
        form.Add( "in_reply_to_status_id", replyToId.ToString() );&#xD;
    }&#xD;
&#xD;
    HttpContent content = form.CreateHttpContent();&#xD;
&#xD;
    HttpResponseMessage message = client.Post( "", content );&#xD;
    message.EnsureStatusIsSuccessful();&#xD;
}&lt;/pre&gt;&lt;!--&lt;img src="listing3.png" /&gt;&lt;br /&gt;--&gt;&lt;p&gt;&#xD;
This time we create an HTML form using the HttpUrlEncodedForm class. We set the status&#xD;
field to our new status. If this status as a response to a previous tweet then we&#xD;
add the in_reply_to_status_id so Twitter knows to add a "in reply to..." tag to the&#xD;
tweet.&#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
And there you have it. Working with the Twitter REST API is really quite straightforward.&#xD;
If you use the REST Starter Kit it's downright easy.&#xD;
&lt;/p&gt;&lt;h3&gt;&#xD;
The Real World Intrudes&#xD;
&lt;/h3&gt;&lt;p&gt;&#xD;
But wait a minute. This is reality and building bulletproof applications is never&#xD;
that simple. There are at least five significant gotchas you have to address in practice&#xD;
when working with Twitter and the REST Starter Kit.&#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
1. There will be times when Twitter is unavailable. You have to be ready for crashes&#xD;
and other types of randomness.&#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
Twitter is one of those sites that can barely handle the traffic it is receiving.&#xD;
With its 1400% growth, this isn't getting much better. So you must program defensively&#xD;
and assume that many of your API requests will fail.&#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
2. The Twitter API is a free service. By default, you are limited to a small number&#xD;
of requests per hour. Many of the limits are around 150 API calls / hour. You may&#xD;
need to carefully design your application to work within the limits. Some applications&#xD;
simply need more data than this permits. For example, .NET Dev Buzz [&lt;a href="http://dotnet.ubbuzz.com/" target="_blank"&gt;http://dotnet.ubbuzz.com/&lt;/a&gt;]&#xD;
has to track thousands of users. In that case, you will have to get your application&#xD;
white listed with Twitter. You can do that here:&#xD;
&lt;/p&gt;&lt;p style="margin-left: 40px;"&gt;&lt;a href="http://twitter.com/help/request_whitelisting" target="_blank"&gt;http://twitter.com/help/request_whitelisting&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&#xD;
3. The date-time format used by the Twitter API is not directly parseable in .NET.&#xD;
The format returned is in the format "Fri Feb 01 18:18:08 +0000 2008". But if we change&#xD;
this to "Fri Feb 01 +0000 2008 18:18:08" it is parsable. So you might need to adjust&#xD;
these date-time values.&#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
4. You will get 417 error codes when you try to talk to Twitter using the default&#xD;
configuration. The fix is not immediately apparent, but it is very simple. So if you&#xD;
see the following error:&#xD;
&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;i&gt;System.ArgumentOutOfRangeException: ExpectationFailed (417) is not one of the following:&#xD;
OK (200), Created (201), Accepted (202), NonAuthoritativeInformation (203), NoContent&#xD;
(204), ResetContent (205), PartialContent (206) at Microsoft.Http.HttpMessageExtensions.EnsuRESTatusIs()&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&#xD;
Just to set the following property: &lt;b&gt;ServicePointManager.Expect100Continue = false&lt;/b&gt;;&#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
5. "Paste XML as Types" doesn't entirely work. For some reason, certain messages from&#xD;
Twitter are not deserializable to the types generated with this command. My experience&#xD;
was that I didn't actually care about the data causing the problem. So I just removed&#xD;
that part of the generated type. You may have to subscribe to the XmlSerializer error&#xD;
events to prevent exceptions.&#xD;
&lt;/p&gt;&lt;h3&gt;&#xD;
Conclusions&#xD;
&lt;/h3&gt;&lt;p&gt;&#xD;
I hope you now have a greater appreciation for what you can do with Twitter and how&#xD;
it can help you build your brand or build engaging applications. We've used the REST&#xD;
Starter Kit to make it easy to consume the Twitter API. You've even seen some of the&#xD;
odd things that can go wrong and how to fix them. Don't forget to download the sample&#xD;
application here:&#xD;
&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.michaelckennedy.com/Samples/SampleStatusUpdater.zip" target="_blank"&gt; http://www.michaelckennedy.com/Samples/SampleStatusUpdater.zip&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&#xD;
Now get out there and build something cool. &#xD;
&lt;/p&gt;&lt;img width="0" height="0" src="http://www.michaelckennedy.net/blog/aggbug.ashx?id=7b884725-09f5-421e-ab4e-4f76c9d5f761"&gt;&lt;/img&gt;&lt;br&gt;&lt;hr&gt;&lt;/hr&gt;&#xD;
All content copyright Michael C. Kennedy. All information, source code, and especially&#xD;
tools are provided as is and on a "use at your own risk" basis.&lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=IlQU52TO5tg:hDsrWU23Q08:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=IlQU52TO5tg:hDsrWU23Q08:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=IlQU52TO5tg:hDsrWU23Q08:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=IlQU52TO5tg:hDsrWU23Q08:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=IlQU52TO5tg:hDsrWU23Q08:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=IlQU52TO5tg:hDsrWU23Q08:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=IlQU52TO5tg:hDsrWU23Q08:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=IlQU52TO5tg:hDsrWU23Q08:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=IlQU52TO5tg:hDsrWU23Q08:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=IlQU52TO5tg:hDsrWU23Q08:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=IlQU52TO5tg:hDsrWU23Q08:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MichaelCKennedysWeblog/~4/IlQU52TO5tg" height="1" width="1"/&gt;</description>
      <comments>http://www.michaelckennedy.net/blog/CommentView,guid,7b884725-09f5-421e-ab4e-4f76c9d5f761.aspx</comments>
      <category>Articles</category>
      <category>DevelopMentor</category>
      <category>web2.0</category>
    <feedburner:origLink>http://www.michaelckennedy.net/blog/2009/08/07/ArticleBuildingATwitterApplicationInNET.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.michaelckennedy.net/blog/Trackback.aspx?guid=e6f659c7-8464-40bf-a896-9fe418cabccb</trackback:ping>
      <pingback:server>http://www.michaelckennedy.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.michaelckennedy.net/blog/PermaLink,guid,e6f659c7-8464-40bf-a896-9fe418cabccb.aspx</pingback:target>
      <dc:creator>Michael Kennedy</dc:creator>
      <wfw:comment>http://www.michaelckennedy.net/blog/CommentView,guid,e6f659c7-8464-40bf-a896-9fe418cabccb.aspx</wfw:comment>
      <wfw:commentRss>http://www.michaelckennedy.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=e6f659c7-8464-40bf-a896-9fe418cabccb</wfw:commentRss>
      <slash:comments>3</slash:comments>
      
      <title>Keep up with DevelopMentor on Twitter</title>
      <guid isPermaLink="false">http://www.michaelckennedy.net/blog/PermaLink,guid,e6f659c7-8464-40bf-a896-9fe418cabccb.aspx</guid>
      <link>http://feedproxy.google.com/~r/MichaelCKennedysWeblog/~3/uXL0_6JFAZM/KeepUpWithDevelopMentorOnTwitter.aspx</link>
      <pubDate>Thu, 23 Jul 2009 22:42:04 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;img src="http://www.develop.com/media/images/DM_Twitter.png" align="right"&gt;&lt;/img&gt; You&#xD;
may know that I work for &lt;a target="_blank" href="http://develop.com"&gt;DevelopMentor&lt;/a&gt; where&#xD;
I'm an instructor in the .NET curriculum (among other cool things I do there). You&#xD;
probably also know I'm kind of loopy for Twitter as evidenced by my Twitter page and&#xD;
.NET community site driven by Twitter:&lt;br&gt;&lt;br&gt;&lt;a target="_blank" href="http://twitter.com/mkennedy"&gt;http://twitter.com/mkennedy&lt;/a&gt;&lt;br&gt;&lt;a target="_blank" href="http://dotnet.ubbuzz.com/"&gt;http://dotnet.ubbuzz.com/&lt;/a&gt;&lt;br&gt;&lt;br&gt;&#xD;
Today those two things came together in a big way. Introducing DevelopMentor's Twitter&#xD;
presence:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;b&gt; @dm_the_company&lt;/b&gt;&#xD;
          &lt;br&gt;&#xD;
          &lt;a target="_blank" href="http://twitter.com/dm_the_company"&gt;http://twitter.com/dm_the_company&lt;/a&gt;&#xD;
          &lt;br&gt;&#xD;
          &lt;br&gt;&#xD;
I encourage you get out there and &lt;b&gt;follow us&lt;/b&gt;! Here you will see all the combined&#xD;
Twitter messages of most of the DevelopMentor instructors as well as a couple of messages&#xD;
from DevelopMentor itself. You'll get the chance to keep on top of the world as viewed&#xD;
by some of the smartest people I've had the chance to work with: the DM instructors!&#xD;
You'll see which instructor posted any given message with an attribution at the end&#xD;
(either "via @marksm" or ^MS depending on the available space).&lt;br&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
I'm excited about this not just because I think it is cool and useful (and has to&#xD;
do with Twitter :) ), but over the last few days I'm the guy who wrote the back-end&#xD;
systems to make this all go. It was a short but fun project. It's a real testament&#xD;
to .NET that this was mostly written an hour.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
After you follow @dm_the_company you might want to interact with some of the instructors&#xD;
directly. Here's our Twitter accounts in a single place for your reference:&#xD;
&lt;/p&gt;&#xD;
        &lt;blockquote&gt;&#xD;
          &lt;p&gt;&#xD;
            &lt;a target="_blank" href="http://twitter.com/bmaso"&gt;http://twitter.com/bmaso&lt;/a&gt;&#xD;
            &lt;br&gt;&#xD;
            &lt;a target="_blank" href="http://twitter.com/danamiga"&gt;http://twitter.com/danamiga&lt;/a&gt;&#xD;
            &lt;br&gt;&#xD;
            &lt;a target="_blank" href="http://twitter.com/jason_diamond"&gt;http://twitter.com/jason_diamond&lt;/a&gt;&#xD;
            &lt;br&gt;&#xD;
            &lt;a target="_blank" href="http://twitter.com/jplane"&gt;http://twitter.com/jplane&lt;/a&gt;&#xD;
            &lt;br&gt;&#xD;
            &lt;a target="_blank" href="http://twitter.com/markblomsma"&gt;http://twitter.com/markblomsma&lt;/a&gt;&#xD;
            &lt;br&gt;&#xD;
            &lt;a target="_blank" href="http://twitter.com/marksm"&gt;http://twitter.com/marksm&lt;/a&gt;&#xD;
            &lt;br&gt;&#xD;
            &lt;a target="_blank" href="http://twitter.com/mauricedb"&gt;http://twitter.com/mauricedb&lt;/a&gt;&#xD;
            &lt;br&gt;&#xD;
            &lt;a target="_blank" href="http://twitter.com/mkennedy"&gt;http://twitter.com/mkennedy&lt;/a&gt;&#xD;
            &lt;br&gt;&#xD;
            &lt;a target="_blank" href="http://twitter.com/nielsberglund"&gt;http://twitter.com/nielsberglund&lt;/a&gt;&#xD;
            &lt;br&gt;&#xD;
            &lt;a target="_blank" href="http://twitter.com/richardblewett"&gt;http://twitter.com/richardblewett&lt;/a&gt;&#xD;
            &lt;br&gt;&#xD;
            &lt;a target="_blank" href="http://twitter.com/tonysneed"&gt;http://twitter.com/tonysneed&lt;/a&gt;&#xD;
            &lt;br&gt;&#xD;
            &lt;a target="_blank" href="http://twitter.com/wallacekelly"&gt;http://twitter.com/wallacekelly&lt;/a&gt;&#xD;
          &lt;/p&gt;&#xD;
        &lt;/blockquote&gt;&#xD;
        &lt;p&gt;&#xD;
I hope you enjoy the conversations we're bound to have on Twitter. Come be part of&#xD;
it.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Signed: &lt;a href="http://twitter.com/mkennedy"&gt;@mkennedy&lt;/a&gt;&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.michaelckennedy.net/blog/aggbug.ashx?id=e6f659c7-8464-40bf-a896-9fe418cabccb"&gt;&lt;/img&gt;&#xD;
        &lt;br&gt;&#xD;
        &lt;hr&gt;&lt;/hr&gt;&#xD;
All content copyright Michael C. Kennedy. All information, source code, and especially&#xD;
tools are provided as is and on a "use at your own risk" basis.&lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=uXL0_6JFAZM:7fwPyKj-gK4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=uXL0_6JFAZM:7fwPyKj-gK4:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=uXL0_6JFAZM:7fwPyKj-gK4:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=uXL0_6JFAZM:7fwPyKj-gK4:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=uXL0_6JFAZM:7fwPyKj-gK4:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=uXL0_6JFAZM:7fwPyKj-gK4:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=uXL0_6JFAZM:7fwPyKj-gK4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=uXL0_6JFAZM:7fwPyKj-gK4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=uXL0_6JFAZM:7fwPyKj-gK4:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=uXL0_6JFAZM:7fwPyKj-gK4:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=uXL0_6JFAZM:7fwPyKj-gK4:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MichaelCKennedysWeblog/~4/uXL0_6JFAZM" height="1" width="1"/&gt;</description>
      <comments>http://www.michaelckennedy.net/blog/CommentView,guid,e6f659c7-8464-40bf-a896-9fe418cabccb.aspx</comments>
      <category>DevelopMentor</category>
      <category>web2.0</category>
    <feedburner:origLink>http://www.michaelckennedy.net/blog/2009/07/23/KeepUpWithDevelopMentorOnTwitter.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.michaelckennedy.net/blog/Trackback.aspx?guid=71611c58-7150-4535-95c6-89d4de6206ce</trackback:ping>
      <pingback:server>http://www.michaelckennedy.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.michaelckennedy.net/blog/PermaLink,guid,71611c58-7150-4535-95c6-89d4de6206ce.aspx</pingback:target>
      <dc:creator>Michael Kennedy</dc:creator>
      <wfw:comment>http://www.michaelckennedy.net/blog/CommentView,guid,71611c58-7150-4535-95c6-89d4de6206ce.aspx</wfw:comment>
      <wfw:commentRss>http://www.michaelckennedy.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=71611c58-7150-4535-95c6-89d4de6206ce</wfw:commentRss>
      <slash:comments>4</slash:comments>
      
      <title>Gmail New Mail Notifications for Windows 7</title>
      <guid isPermaLink="false">http://www.michaelckennedy.net/blog/PermaLink,guid,71611c58-7150-4535-95c6-89d4de6206ce.aspx</guid>
      <link>http://feedproxy.google.com/~r/MichaelCKennedysWeblog/~3/tXjr9uI9tWE/GmailNewMailNotificationsForWindows7.aspx</link>
      <pubDate>Sat, 11 Jul 2009 05:44:21 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
[Update: Renamed this tool from Gmailer to Gmail 7 due to pre-exiting product name&#xD;
conflicts]&lt;br&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
I've been using Windows 7 as my sole operating system since Beta 1 in January. I'm&#xD;
completely loving it and I was pleased to see how many apps worked seamlessly on it.&#xD;
One that didn't and I really miss is &lt;a href="http://toolbar.google.com/gmail-helper/notifier_windows.html" target="_blank"&gt;Gmail&#xD;
Notifier&lt;/a&gt;. No matter how I try, I always get this: &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;img src="http://www.michaelckennedy.net/blog/content/binary/gmail%20error.png"&gt;&lt;/img&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
It's insane to me that $130B company can't provide any more than this outdated tool&#xD;
for this job, but I digress...&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
I've looked and looked for a replacement and they are either no longer online, are&#xD;
crappy applications, and so on. Finally I decided to take matters into my own hands.&#xD;
Introducing a clean, simple, unobtrusive, and free Gmail notification application&#xD;
that &lt;strong&gt;works on Windows 7&lt;/strong&gt; - &lt;i&gt;Gmail 7&lt;/i&gt;:&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;img src="http://www.michaelckennedy.net/blog/content/binary/GmailerSettings.png"&gt;&lt;/img&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
          &lt;i&gt;Gmail 7&lt;/i&gt; simply runs in your tray and plays the Windows new mail sound when&#xD;
mail comes in to your Gmail account.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
New Mail:&lt;br&gt;&lt;img src="http://www.michaelckennedy.net/blog/content/binary/NewMailSnap.png"&gt;&lt;/img&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
No New Mail:&lt;br&gt;&lt;img src="http://www.michaelckennedy.net/blog/content/binary/NoMailSnap.png"&gt;&lt;/img&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
That's pretty unobtrusive right? Your account info is encrypted and stored in your&#xD;
user profile and all network access uses SSL.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Download all 41 KB of Gmail 7 here: &lt;a href="/Downloads/Tools/GMailer/GMail7.zip"&gt;Gmail7.zip&lt;/a&gt;&lt;br&gt;&lt;/p&gt;&#xD;
        &lt;p style="color: gray;"&gt;&#xD;
          &lt;font size="1"&gt;Requires .NET 2.0 (built into Vista and Windows 7)&lt;/font&gt;&#xD;
        &lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Just extract the folder to its final resting place and run it - select "Launch at&#xD;
login" if you want that.&#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
It even comes with some cool ways to view your email by double-clicking the tray icon.&lt;br&gt;&lt;a href="http://www.michaelckennedy.net/blog/content/binary/GmailerLaunchOptinos.png" target="_blank"&gt;&lt;img src="http://www.michaelckennedy.net/blog/content/binary/GmailerLaunchOptions_small.png" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
Also thanks goes to &lt;a href="http://ryanscook.com/adminsBlog/2005/05/c-net-gmail-tools_26.html"&gt;Ryan&#xD;
Cook&lt;/a&gt; for use of his Gmail C# tools as the basis for part of my project.&#xD;
&lt;/p&gt;&#xD;
        &lt;img width="0" height="0" src="http://www.michaelckennedy.net/blog/aggbug.ashx?id=71611c58-7150-4535-95c6-89d4de6206ce"&gt;&lt;/img&gt;&#xD;
        &lt;br&gt;&#xD;
        &lt;hr&gt;&lt;/hr&gt;&#xD;
All content copyright Michael C. Kennedy. All information, source code, and especially&#xD;
tools are provided as is and on a "use at your own risk" basis.&lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=tXjr9uI9tWE:1VD_Rj1rhCg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=tXjr9uI9tWE:1VD_Rj1rhCg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=tXjr9uI9tWE:1VD_Rj1rhCg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=tXjr9uI9tWE:1VD_Rj1rhCg:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=tXjr9uI9tWE:1VD_Rj1rhCg:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=tXjr9uI9tWE:1VD_Rj1rhCg:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=tXjr9uI9tWE:1VD_Rj1rhCg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=tXjr9uI9tWE:1VD_Rj1rhCg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=tXjr9uI9tWE:1VD_Rj1rhCg:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=tXjr9uI9tWE:1VD_Rj1rhCg:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=tXjr9uI9tWE:1VD_Rj1rhCg:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MichaelCKennedysWeblog/~4/tXjr9uI9tWE" height="1" width="1"/&gt;</description>
      <comments>http://www.michaelckennedy.net/blog/CommentView,guid,71611c58-7150-4535-95c6-89d4de6206ce.aspx</comments>
      <category>Tools</category>
    <feedburner:origLink>http://www.michaelckennedy.net/blog/2009/07/11/GmailNewMailNotificationsForWindows7.aspx</feedburner:origLink></item>
    <item>
      <trackback:ping>http://www.michaelckennedy.net/blog/Trackback.aspx?guid=210f6623-b67e-4b6b-835e-1576bc2cfb3c</trackback:ping>
      <pingback:server>http://www.michaelckennedy.net/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.michaelckennedy.net/blog/PermaLink,guid,210f6623-b67e-4b6b-835e-1576bc2cfb3c.aspx</pingback:target>
      <dc:creator>Michael Kennedy</dc:creator>
      <wfw:comment>http://www.michaelckennedy.net/blog/CommentView,guid,210f6623-b67e-4b6b-835e-1576bc2cfb3c.aspx</wfw:comment>
      <wfw:commentRss>http://www.michaelckennedy.net/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=210f6623-b67e-4b6b-835e-1576bc2cfb3c</wfw:commentRss>
      
      <title>ASP.NET Routing in Windows Azure Using WebForms</title>
      <guid isPermaLink="false">http://www.michaelckennedy.net/blog/PermaLink,guid,210f6623-b67e-4b6b-835e-1576bc2cfb3c.aspx</guid>
      <link>http://feedproxy.google.com/~r/MichaelCKennedysWeblog/~3/v9tXq5TVNqc/ASPNETRoutingInWindowsAzureUsingWebForms.aspx</link>
      <pubDate>Wed, 27 May 2009 21:53:18 GMT</pubDate>
      <description>&lt;body xmlns="http://www.w3.org/1999/xhtml"&gt;&#xD;
        &lt;p&gt;&#xD;
I'm a huge fan of ASP.NET Routing. It gained popularity as the part of &lt;a href="http://www.asp.net/mvc/" target="_blank"&gt;ASP.NET&#xD;
MVC &lt;/a&gt;which channels requests for a given URL to the right controller action. In&#xD;
a wise move, Microsoft moved the routing infrastructure out of &lt;a href="http://www.asp.net/mvc/" target="_blank"&gt;ASP.NET&#xD;
MVC &lt;/a&gt; and into its own assembly with the release of .NET 3.5 SP1. &#xD;
&lt;/p&gt;&#xD;
        &lt;p&gt;&#xD;
With ASP.NET Routing you can construct search engine optimized and human friendly&#xD;
URLs such as these:&lt;br&gt;&lt;/p&gt;&#xD;
        &lt;div style="position: relative; left: 15px;"&gt;&#xD;
          &lt;a href="http://dotnet.ubbuzz.com/tag/everything" target="_blank"&gt;http://dotnet.ubbuzz.com/tag/everything&lt;/a&gt;&#xD;
          &lt;br&gt;&#xD;
          &lt;a href="http://dotnet.ubbuzz.com/tag/Azure" target="_blank"&gt;http://dotnet.ubbuzz.com/tag/Azure&lt;/a&gt;&#xD;
          &lt;br&gt;&#xD;
          &lt;a href="http://dotnet.ubbuzz.com/user/codinghorror" target="_blank"&gt;http://dotnet.ubbuzz.com/user/codinghorror&lt;/a&gt;&#xD;
          &lt;br&gt;&#xD;
        &lt;/div&gt;&#xD;
        &lt;br&gt;&#xD;
Here part of the URL (&lt;b&gt;tag &lt;/b&gt;or &lt;b&gt;user&lt;/b&gt;) selects the page and part of the&#xD;
URL (&lt;b&gt;everything&lt;/b&gt; or &lt;b&gt;codinghorror&lt;/b&gt;) are effectively query parameters to&#xD;
the page. &#xD;
&lt;p&gt;&lt;/p&gt;&lt;p&gt;&#xD;
This is well documented in the &lt;a href="http://www.asp.net/mvc/" target="_blank"&gt;ASP.NET&#xD;
MVC &lt;/a&gt; world running on your server - you can't get anything done without it in&#xD;
MVC. But what about &lt;a href="http://www.azure.com" target="_blank"&gt;Windows Azure&lt;/a&gt;?&#xD;
What if you don't want ASP.NET MVC? What if you're a traditional type of person and&#xD;
want all the goodness that comes with what is now called ASP.NET WebForms (aka "normal&#xD;
ASP.NET")? &#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
In this brief post, I'll cover how to use ASP.NET routing and ASP.NET WebForms in&#xD;
Azure. The &lt;a href="http://www.michaelckennedy.com/Samples/AzureRoutingSample.zip"&gt;sample&#xD;
project can be downloaded&lt;/a&gt; if you want to follow along. &lt;a href="http://haacked.com/archive/2008/03/11/using-routing-with-webforms.aspx" target="_blank"&gt;Phil&#xD;
Haack&lt;/a&gt; has written a good post on using routing alongside ASP.NET WebForms so I&#xD;
won't cover too much background information.&lt;br&gt;&lt;/p&gt;&lt;div style="position: relative; left: 15px;"&gt;&lt;a href="http://haacked.com/archive/2008/03/11/using-routing-with-webforms.aspx" target="_blank"&gt;http://haacked.com/archive/2008/03/11/using-routing-with-webforms.aspx&lt;/a&gt;&lt;br&gt;&lt;/div&gt;&lt;br&gt;&lt;strong&gt;How does this change for Azure?&lt;/strong&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&#xD;
The short answer is that it doesn't. If you get routing working for IIS 7 in your&#xD;
web app, you can effectively deploy it to Azure. But the steps always felt convoluted&#xD;
to me when reading others' write-ups on this. So let's run through converting a Windows&#xD;
Azure Web Role (essentially a "stock" ASP.NET WebForms app) to use routing in Azure. &#xD;
&lt;/p&gt;&lt;p&gt;&#xD;
First you'll need the Azure SDK and Visual Studio tools:&lt;br&gt;&lt;/p&gt;&lt;div style="position: relative; left: 15px;"&gt;&lt;a href="http://www.microsoft.com/azure/windowsazurefordevelopers/default.aspx" target="_blank"&gt;http://www.microsoft.com/azure/windowsazurefordevelopers/default.aspx&lt;/a&gt;&lt;br&gt;&lt;/div&gt;&lt;br&gt;&lt;ol&gt;&lt;li&gt;&#xD;
Next, create a new solution in Visual Studio by choosing &lt;b&gt;Cloud Service-&amp;gt;Web&#xD;
and Worker Cloud Service&lt;/b&gt;.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;&#xD;
Add a new &lt;b&gt;Global.asax &lt;/b&gt;file to your web role project.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;&#xD;
Add a reference to &lt;b&gt;System.Web.Routing &lt;/b&gt;and &lt;b&gt;System.Web.Abstractions&lt;/b&gt; in&#xD;
your web role project.&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;&#xD;
Define a custom class that derives from &lt;b&gt;IRouteHandler &lt;/b&gt;which will map URL parameters&#xD;
into the HttpContext for use in your pages:&lt;br&gt;&lt;pre class="brush: csharp"&gt;internal class CustomRoute : IRouteHandler&#xD;
{&#xD;
    public CustomRoute(string virtualPath)&#xD;
    {&#xD;
        VirtualPath = virtualPath;&#xD;
    }&#xD;
&#xD;
    public string VirtualPath { get; private set; }&#xD;
&#xD;
    public IHttpHandler GetHttpHandler(RequestContext requestContext)&#xD;
    {&#xD;
        foreach ( var aux in requestContext.RouteData.Values )&#xD;
        {&#xD;
            HttpContext.Current.Items[aux.Key] = aux.Value;&#xD;
        }&#xD;
&#xD;
        return BuildManager.CreateInstanceFromVirtualPath(&#xD;
                   VirtualPath, typeof( Page ) ) as IHttpHandler;&#xD;
    }&#xD;
}&#xD;
&lt;/pre&gt;&lt;!--
&lt;pre&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;internal&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;class&lt;/span&gt; CustomRoute : IRouteHandler
{
    &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; CustomRoute(&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;string&lt;/span&gt; virtualPath)
    {
        VirtualPath &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; virtualPath;
    }

    &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;string&lt;/span&gt; VirtualPath { get; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;private&lt;/span&gt; set; }

    &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;public&lt;/span&gt; IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;foreach&lt;/span&gt; (var aux &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;in&lt;/span&gt; requestContext.RouteData.Values)
        {
            HttpContext.Current.Items[aux.Key] &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; aux.Value;
        }

        &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;return&lt;/span&gt; BuildManager.CreateInstanceFromVirtualPath(
                   VirtualPath, &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;typeof&lt;/span&gt; (Page)) &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;as&lt;/span&gt; IHttpHandler;
    }
}
&lt;/span&gt;&lt;/pre&gt;

--&gt;&lt;/li&gt;&lt;li&gt;&#xD;
Register these routes in the &lt;b&gt;Application_Start &lt;/b&gt;method of your Global.asax:&lt;br&gt;&lt;pre class="brush: csharp"&gt;protected void Application_Start(object sender, EventArgs e)&#xD;
{&#xD;
    RouteTable.Routes.Add( "ShowName",&#xD;
           new Route(&#xD;
            "naming/show/{name}",&#xD;
            new CustomRoute( "~/ShowName.aspx" )&#xD;
            ) );&#xD;
&#xD;
    RouteTable.Routes.Add( "CreateAccount",&#xD;
           new Route(&#xD;
            "account/begin",&#xD;
            new CustomRoute( "~/Account.aspx" )&#xD;
            ) );&#xD;
&#xD;
    RouteTable.Routes.Add( "Home",&#xD;
           new Route(&#xD;
            "home",&#xD;
            new CustomRoute( "~/Default.aspx" )&#xD;
            ) );&#xD;
}&#xD;
&lt;/pre&gt;&lt;!--
&lt;pre&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;protected&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; Application_Start(&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;object&lt;/span&gt; sender, EventArgs e)
{
    RouteTable.Routes.Add( &lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"ShowName"&lt;/span&gt;,
           &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Route(
            &lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"naming/show/{name}"&lt;/span&gt;,
            &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; CustomRoute( &lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"~/ShowName.aspx"&lt;/span&gt; )
            ) );

    RouteTable.Routes.Add( &lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"CreateAccount"&lt;/span&gt;,
           &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Route(
            &lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"account/begin"&lt;/span&gt;,
            &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; CustomRoute( &lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"~/Account.aspx"&lt;/span&gt; )
            ) );

    RouteTable.Routes.Add( &lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"Home"&lt;/span&gt;,
           &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; Route(
            &lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"home"&lt;/span&gt;,
            &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;new&lt;/span&gt; CustomRoute( &lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"~/Default.aspx"&lt;/span&gt; )
            ) );
}
&lt;/span&gt;&lt;/pre&gt;
--&gt;&#xD;
Now if you run your app, you might expect the routing infrastructure to work. Inside&#xD;
the ASP.NET Dev Server (aka cassini) this will likely work. But in the Azure Development&#xD;
Fabric you'll see this:&lt;br&gt;&lt;br&gt;&lt;a href="http://www.michaelckennedy.net/blog/content/binary/NoHandlerErrorAnnotated.png"&gt;&lt;img src="http://www.michaelckennedy.net/blog/content/binary/NoHandlerErrorAnnotated.png" width="407"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br&gt;&lt;br&gt;&#xD;
The problem is you need to tell IIS 7.5 to get out of the way and let the request&#xD;
get to ASP.NET. &#xD;
&lt;br&gt;&lt;br&gt;&lt;/li&gt;&lt;li&gt;&#xD;
We'll define a class to short-circuit the IIS validation&lt;br&gt;&lt;pre class="brush: csharp"&gt;class Iis7RoutingHandler : UrlRoutingHandler&#xD;
{&#xD;
    protected override void VerifyAndProcessRequest(&#xD;
        IHttpHandler httpHandler, HttpContextBase httpContext)&#xD;
    {&#xD;
    }&#xD;
}&lt;/pre&gt;&lt;!--
&lt;pre&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;class&lt;/span&gt; Iis7RoutingHandler : UrlRoutingHandler
{
    &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;protected&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;override&lt;/span&gt; &lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;void&lt;/span&gt; VerifyAndProcessRequest(
        IHttpHandler httpHandler, HttpContextBase httpContext)
    {
    }
}&lt;/span&gt;
&lt;/pre&gt;--&gt;&lt;/li&gt;&lt;li&gt;&#xD;
Modify the web.config by adding a handler and module to the &lt;strong&gt;system.webServer&lt;/strong&gt; section:&lt;br&gt;&lt;pre class="brush: xml"&gt;&lt;system.webserver&gt;&lt;modules runallmanagedmodulesforallrequests="true"&gt;&#xD;
... &#xD;
&lt;add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, &amp;#xA;     System.Web.Routing, Version=3.5.0.0, &amp;#xA;     Culture=neutral, &amp;#xA;     PublicKeyToken=31BF3856AD364E35"&gt;&lt;/add&gt;&lt;handlers&gt;&lt;add name="UrlRoutingHandler" precondition="integratedMode" verb="*" path="UrlRouting.axd" type="WebCore.Iis7RoutingHandler, WebCore"&gt;&lt;/add&gt;&lt;/handlers&gt;&lt;/modules&gt;&lt;/system.webserver&gt;&lt;/pre&gt;&lt;!--
&lt;pre&gt;&amp;lt;system.webServer&amp;gt;
   &amp;lt;modules &lt;strong&gt;runAllManagedModulesForAllRequests="true"&lt;/strong&gt;&amp;gt;
   ...
      &lt;strong&gt;&amp;lt;add name="UrlRoutingModule" 
         type="System.Web.Routing.UrlRoutingModule, 
         System.Web.Routing, Version=3.5.0.0, 
         Culture=neutral, 
         PublicKeyToken=31BF3856AD364E35" /&amp;gt;&lt;/strong&gt;
   &amp;lt;/modules&amp;gt;
   &amp;lt;handlers&amp;gt;
      &lt;strong&gt;&amp;lt;add 
         name="UrlRoutingHandler" 
         preCondition="integratedMode" 
         verb="*" 
         path="UrlRouting.axd" 
         type="WebCore.Iis7RoutingHandler, WebCore"/&amp;gt;&lt;/strong&gt;
   &amp;lt;/handlers&amp;gt;
 &amp;lt;/system.webServer&amp;gt;
&lt;/pre&gt;
--&gt;&lt;/li&gt;&lt;li&gt;&#xD;
Finally, we need to recover the data passed to the page. For example, in the sample&#xD;
project we have:&lt;br&gt;&lt;br&gt;&#xD;
route: &lt;b&gt;/naming/show/{name}&lt;/b&gt;&lt;br&gt;&#xD;
example:&lt;b&gt; /naming/show/michael-kennedy&lt;/b&gt;&lt;br&gt;&lt;br&gt;&#xD;
How will our page access the value of name? Recall that our custom route stashes the&#xD;
values in HttpContext.Current.Items. We'll just pull them back out as follows in our&#xD;
Page_Load method of our ASPX class:&lt;br&gt;&lt;pre&gt;&lt;span style="color: Black; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;LabelName.Text &lt;span style="color: Red; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;=&lt;/span&gt; (&lt;span style="color: Blue; background-color: transparent; font-family: Courier New; font-size: 11px;"&gt;string&lt;/span&gt;)HttpContext.Current.Items[&lt;span style="color: rgb(102, 102, 102); background-color: rgb(228, 228, 228); font-family: Courier New; font-size: 11px;"&gt;"name"&lt;/span&gt;];&lt;br&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ol&gt;&#xD;
That's it! You can see our routes working in our WebForms app running in Azure (well,&#xD;
technically the screenshot is the dev fabric - but it works in the cloud as well):&lt;br&gt;&lt;br&gt;&lt;img src="http://www.michaelckennedy.net/blog/content/binary/RoutingInActionAnnotated.png"&gt;&lt;/img&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&#xD;
Download the source and try it for yourself: &lt;a href="http://www.michaelckennedy.com/Samples/AzureRoutingSample.zip"&gt;AzureRoutingSample.zip&lt;/a&gt; (136&#xD;
KB) &#xD;
&lt;br&gt;&lt;/p&gt;&lt;img width="0" height="0" src="http://www.michaelckennedy.net/blog/aggbug.ashx?id=210f6623-b67e-4b6b-835e-1576bc2cfb3c"&gt;&lt;/img&gt;&lt;br&gt;&lt;hr&gt;&lt;/hr&gt;&#xD;
All content copyright Michael C. Kennedy. All information, source code, and especially&#xD;
tools are provided as is and on a "use at your own risk" basis.&lt;/body&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=v9tXq5TVNqc:VEmCXhU8FkU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=v9tXq5TVNqc:VEmCXhU8FkU:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=v9tXq5TVNqc:VEmCXhU8FkU:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=v9tXq5TVNqc:VEmCXhU8FkU:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=v9tXq5TVNqc:VEmCXhU8FkU:D7DqB2pKExk"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=v9tXq5TVNqc:VEmCXhU8FkU:D7DqB2pKExk" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=v9tXq5TVNqc:VEmCXhU8FkU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=v9tXq5TVNqc:VEmCXhU8FkU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=v9tXq5TVNqc:VEmCXhU8FkU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?a=v9tXq5TVNqc:VEmCXhU8FkU:gIN9vFwOqvQ"&gt;&lt;img src="http://feeds.feedburner.com/~ff/MichaelCKennedysWeblog?i=v9tXq5TVNqc:VEmCXhU8FkU:gIN9vFwOqvQ" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/MichaelCKennedysWeblog/~4/v9tXq5TVNqc" height="1" width="1"/&gt;</description>
      <comments>http://www.michaelckennedy.net/blog/CommentView,guid,210f6623-b67e-4b6b-835e-1576bc2cfb3c.aspx</comments>
      <category>Articles</category>
      <category>ASP.NET</category>
      <category>Azure</category>
      <category>DevelopMentor</category>
      <category>web2.0</category>
    <feedburner:origLink>http://www.michaelckennedy.net/blog/2009/05/27/ASPNETRoutingInWindowsAzureUsingWebForms.aspx</feedburner:origLink></item>
  </channel>
</rss>
