﻿<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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:pingback="http://madskills.com/public/xml/rss/module/pingback/" version="2.0">
  <channel>
    <title>ComputerZen.com - Scott Hanselman's Weblog</title>
    <link>http://www.hanselman.com/blog/</link>
    <description>Scott Hanselman's Thoughts on .NET, WebServices, and Life</description>
    <copyright>Scott Hanselman</copyright>
    <lastBuildDate>Sun, 05 Dec 2004 20:22:20 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 1.6.4121.0</generator>
    <managingEditor>scott@hanselman.com</managingEditor>
    <webMaster>scott@hanselman.com</webMaster>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=0a883ebd-545a-458f-8a03-383065559926</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=0a883ebd-545a-458f-8a03-383065559926</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=0a883ebd-545a-458f-8a03-383065559926</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=0a883ebd-545a-458f-8a03-383065559926</wfw:commentRss>
      <slash:comments>0</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
        </p>
        <p>
      If you are receiving this post, you may be subscribed to my Radio UserLand RSS Feed
      (that I've been silently updating for over a year.)
   </p>
        <p>
      It's time to stop using that feed as I'm going to stop updating it. Please use this
      URL for your RSS Feed:
   </p>
        <p>
          <a href="http://www.hanselman.com/blog/SyndicationService.asmx/GetRss">http://www.hanselman.com/blog/SyndicationService.asmx/GetRss</a>
        </p>
        <p>
      Thanks!
   </p>
        <p>
      Scott Hanselman
   </p>
        <img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=0a883ebd-545a-458f-8a03-383065559926" />
      </body>
      <title>ATTENTION: RSS Subscribers to ComputerZen.com using my Radio RSS FEED</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=0a883ebd-545a-458f-8a03-383065559926</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=0a883ebd-545a-458f-8a03-383065559926</link>
      <pubDate>Sun, 05 Dec 2004 20:22:20 GMT</pubDate>
      <description>&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
   If you are receiving this post, you may be subscribed to my Radio UserLand RSS Feed
   (that I've been silently updating for over a year.)
&lt;/p&gt;
&lt;p&gt;
   It's time to stop using that feed as I'm going to stop updating it. Please use this
   URL for your RSS Feed:
&lt;/p&gt;
&lt;p&gt;
   &lt;a href="http://www.hanselman.com/blog/SyndicationService.asmx/GetRss"&gt;http://www.hanselman.com/blog/SyndicationService.asmx/GetRss&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
   Thanks!
&lt;/p&gt;
&lt;p&gt;
   Scott Hanselman
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=0a883ebd-545a-458f-8a03-383065559926"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=0a883ebd-545a-458f-8a03-383065559926</comments>
      <category>Musings</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=75a25837-de4f-403f-ad5a-e7d397be0ad0</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=75a25837-de4f-403f-ad5a-e7d397be0ad0</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=75a25837-de4f-403f-ad5a-e7d397be0ad0</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=75a25837-de4f-403f-ad5a-e7d397be0ad0</wfw:commentRss>
      <slash:comments>0</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
        </p>
        <p>
      I'm surprised I'm just now noticing this. <a href="http://weblogs.asp.net/jgalloway/archive/2004/10/15/242677.aspx">Jon
      Galloway</a> hooked up the apparently unused System.Web.Handler.BatchHandler to an
      httpHandler and was able to precompile all his .ASPX pages. This could be useful during
      deployment to catch any goofs in ASPX code. Certainly not something you want on in
      production lest you be DoS'ed with compilation, but a helpful thing regardless.
   </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <em>To set this up at the machine level, add the following line to the &lt;httpHandlers&gt;
      section of %windir%\Microsoft.NET\Framework\v1.1.4322\CONFIG\machine.config:</em>
          </p>
          <p>
            <font color="#0033cc">
              <em>&lt;add verb="*" path="precompile.axd" type="System.Web.Handlers.BatchHandler"/&gt;</em>
            </font>
          </p>
          <p>
            <em>To set this up at the application level, add the you'll need to create an httpHandlers
      section like so: [</em>
            <a href="http://weblogs.asp.net/jgalloway/archive/2004/10/15/242677.aspx">
              <em>JonGalloway</em>
            </a>
            <em>]</em>
          </p>
          <p>
            <font color="#0033cc">
              <em>&lt;configuration&gt;<br />
        &lt;system.web&gt;<br />
          &lt;httpHandlers&gt;<br />
            &lt;add verb="*" path="precompile.axd" type="System.Web.Handlers.BatchHandler"/&gt;<br />
          &lt;/httpHandlers&gt;<br />
        &lt;/system.web&gt;<br />
      &lt;/configuration&gt;</em>
            </font>
          </p>
        </blockquote>
        <p dir="ltr">
          <strong>Now playing:</strong>
          <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Stevie Wonder">Stevie
      Wonder</a> - <a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=As&amp;artistTerm=Stevie Wonder">As</a></p>
        <img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=75a25837-de4f-403f-ad5a-e7d397be0ad0" />
      </body>
      <title>Precompile.axd in ASP.NET 1.1 with System.Web.Handlers.BatchHandler: A harbinger of ASP.NET 2.0 left vestigially in 1.1?</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=75a25837-de4f-403f-ad5a-e7d397be0ad0</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=75a25837-de4f-403f-ad5a-e7d397be0ad0</link>
      <pubDate>Sun, 05 Dec 2004 01:08:50 GMT</pubDate>
      <description>&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
   I'm surprised I'm just now noticing this. &lt;a href="http://weblogs.asp.net/jgalloway/archive/2004/10/15/242677.aspx"&gt;Jon
   Galloway&lt;/a&gt; hooked up the apparently unused System.Web.Handler.BatchHandler to an
   httpHandler and was able to precompile all his .ASPX pages. This could be useful during
   deployment to catch any goofs in ASPX code. Certainly not something you want on in
   production lest you be DoS'ed with compilation, but a helpful thing regardless.
&lt;/p&gt;
&lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt;
&lt;p&gt;
   &lt;em&gt;To set this up at the machine level, add the following line to the &amp;lt;httpHandlers&amp;gt;
   section of %windir%\Microsoft.NET\Framework\v1.1.4322\CONFIG\machine.config:&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
   &lt;font color="#0033cc"&gt;&lt;em&gt;&amp;lt;add verb="*" path="precompile.axd" type="System.Web.Handlers.BatchHandler"/&amp;gt;&lt;/em&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
   &lt;em&gt;To set this up at the application level, add the you'll need to create an httpHandlers
   section like so: [&lt;/em&gt;&lt;a href="http://weblogs.asp.net/jgalloway/archive/2004/10/15/242677.aspx"&gt;&lt;em&gt;JonGalloway&lt;/em&gt;&lt;/a&gt;&lt;em&gt;]&lt;/em&gt;
&lt;/p&gt;
&lt;p&gt;
   &lt;font color="#0033cc"&gt;&lt;em&gt;&amp;lt;configuration&amp;gt;&lt;br /&gt;
   &amp;nbsp;&amp;nbsp;&amp;lt;system.web&amp;gt;&lt;br /&gt;
   &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;httpHandlers&amp;gt;&lt;br /&gt;
   &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;add&amp;nbsp;verb="*"&amp;nbsp;path="precompile.axd"&amp;nbsp;type="System.Web.Handlers.BatchHandler"/&amp;gt;&lt;br /&gt;
   &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/httpHandlers&amp;gt;&lt;br /&gt;
   &amp;nbsp;&amp;nbsp;&amp;lt;/system.web&amp;gt;&lt;br /&gt;
   &amp;lt;/configuration&amp;gt;&lt;/em&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir="ltr"&gt;
   &lt;strong&gt;Now playing:&lt;/strong&gt; &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?artistTerm=Stevie Wonder"&gt;Stevie
   Wonder&lt;/a&gt; - &lt;a href="http://phobos.apple.com/WebObjects/MZSearch.woa/wa/advancedSearchResults?songTerm=As&amp;amp;artistTerm=Stevie Wonder"&gt;As&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=75a25837-de4f-403f-ad5a-e7d397be0ad0"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=75a25837-de4f-403f-ad5a-e7d397be0ad0</comments>
      <category>ASP.NET</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=8c8cbf02-b25f-4170-9e68-110afdaa46f1</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=8c8cbf02-b25f-4170-9e68-110afdaa46f1</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=8c8cbf02-b25f-4170-9e68-110afdaa46f1</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=8c8cbf02-b25f-4170-9e68-110afdaa46f1</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
      I've pretty much solved the <a href="http://www.hanselman.com/blog/PermaLink.aspx?guid=99b2e3e9-5597-4883-a015-d77c3246a2a8">comment-Spam</a> problem
      (only one person has voiced their distaste so far) but a recently perusal of my logs
      and older posts indicated a ridiculous amount of referral spam.  
   </p>
        <p>
      This is when someone hits a post on your site and has changed/hacked the HTTP Referrer
      Header to indicate where they came from. If your blog adds this referrer to the page,
      as most to, you've just linked to Hot Gay Sex (not that there's anything wrong with
      Hot Sex between consenting adults : ) ) or whatever by their actions. 
   </p>
        <p>
      The story goes when Google comes around, they see that you've linked to them, and
      they get <a href="http://c2.com/cgi/wiki?GoogleJuice">Google Juice</a> via the <a href="http://c2.com/cgi/wiki?PageRank">Page
      Rank System</a>. 
   </p>
        <p>
      Not only is this potentially offensive to my readers, it also obscures the posts and
      comments when they are filled with referrals. 
   </p>
        <p>
          <strong>Potential Solutions:</strong>
        </p>
        <ul>
          <li>
         Stop printing out referrals on my pages. 
      </li>
          <ul>
            <li>
            Personally, I like to see them, and I think they provide value to the reader so they
            can see other places with information of interest. It also promotes cross-linking
            between my peer blogs.</li>
          </ul>
          <li>
         Modify dasBlog to NOT add icky referrals.</li>
          <ul>
            <li>
            This would be idea. However, it will likely be in version 1.7 in some way, either
            via <a href="http://www.jamessnape.me.uk/PermaLink,guid,0b2ea522-a958-4d62-8d68-136808e5ecec.aspx">James
            Snape's whitelist solution</a> (I think a whitelist removes the point of referrals,
            and I'll greatly prefer a keyword-based black list) or some other technique.</li>
            <li>
            I've avoided running a "private build" of dasBlog so far (as evidenced by my care
            in creating the <a href="http://www.hanselman.com/blog/PermaLink.aspx?guid=99b2e3e9-5597-4883-a015-d77c3246a2a8">CAPTCHA
            solution without recompiling</a>) and I'd to continue as such</li>
          </ul>
          <li>
         Clean the .xml files occasionally with a process</li>
          <ul>
            <li>
            This is quick, easy, can be automated, and will work in the short term for me as I
            await dasBlog 1.7.</li>
          </ul>
        </ul>
        <p>
      So, here was an opportunity to use the only dev stuff I have on my home machine, <a href="http://lab.msdn.microsoft.com/express/vcsharp/default.aspx">Visual
      Studio C# 2005 Express</a>. 
   </p>
        <p>
      Here's what I did. Use at your own risk, back up your /content directory, and know
      that this will only have to run on your "*.dayextra.xml" files from dasBlog.
      No error handling, no warrenty, but it worked for me. Enjoy.
   </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <strong>Usage: TrackingFilter "c:\yourdasblogcontentdirectory"</strong>
          </p>
        </blockquote>
        <p dir="ltr" style="MARGIN-RIGHT: 0px">
          <a href="http://www.hanselman.com/blog/content/binary/TrackingFilter.zip">File Attachment:
      TrackingFilter.zip (9 KB)</a> (for VS.NET 2005, I don't know if it works in 2003) 
   </p>
        <p dir="ltr" style="MARGIN-RIGHT: 0px">
          <font color="#ff0000">
            <strong>WARNING: </strong>The words I put in the .config file
      are ; delimited and are <em>unquestionably offensive</em>. Not only do they include
      most of <a href="http://www.erenkrantz.com/Humor/SevenDirtyWords.shtml">George
      Carlin's words</a> but they also include "bloglines" and "artima" because they
      don't provide a value in my referral list.</font>
        </p>
        <img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=8c8cbf02-b25f-4170-9e68-110afdaa46f1" />
      </body>
      <title>Target: Referral Spam in dasBlog</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=8c8cbf02-b25f-4170-9e68-110afdaa46f1</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=8c8cbf02-b25f-4170-9e68-110afdaa46f1</link>
      <pubDate>Sat, 04 Dec 2004 07:37:24 GMT</pubDate>
      <description>&lt;p&gt;
   I've pretty much solved the &lt;a href="http://www.hanselman.com/blog/PermaLink.aspx?guid=99b2e3e9-5597-4883-a015-d77c3246a2a8"&gt;comment-Spam&lt;/a&gt;&amp;nbsp;problem
   (only one person has voiced their distaste so far) but a recently perusal of my logs
   and older posts indicated a ridiculous amount of referral spam.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
   This is when someone hits a post on your site and has changed/hacked the HTTP Referrer
   Header to indicate where they came from. If your blog adds this referrer to the page,
   as most to, you've just linked to Hot Gay Sex (not that there's anything wrong with
   Hot Sex between consenting adults : ) ) or whatever by their actions. 
&lt;/p&gt;
&lt;p&gt;
   The story goes when Google comes around, they see that you've linked to them, and
   they get &lt;a href="http://c2.com/cgi/wiki?GoogleJuice"&gt;Google Juice&lt;/a&gt;&amp;nbsp;via the &lt;a href="http://c2.com/cgi/wiki?PageRank"&gt;Page
   Rank System&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
   Not only is this potentially offensive to my readers, it also obscures the posts and
   comments when they are filled with referrals. 
&lt;/p&gt;
&lt;p&gt;
   &lt;strong&gt;Potential Solutions:&lt;/strong&gt;
&lt;/p&gt;
&lt;ul&gt;
   &lt;li&gt;
      Stop&amp;nbsp;printing out referrals on my pages. 
   &lt;/li&gt;
   &lt;ul&gt;
      &lt;li&gt;
         Personally, I like to see them, and I think they provide value to the reader so they
         can see other places with information of interest. It also promotes cross-linking
         between my peer blogs.&lt;/li&gt;
   &lt;/ul&gt;
   &lt;li&gt;
      Modify dasBlog to NOT add icky referrals.&lt;/li&gt;
   &lt;ul&gt;
      &lt;li&gt;
         This would be idea. However, it will likely be in version 1.7 in some way, either
         via &lt;a href="http://www.jamessnape.me.uk/PermaLink,guid,0b2ea522-a958-4d62-8d68-136808e5ecec.aspx"&gt;James
         Snape's whitelist solution&lt;/a&gt;&amp;nbsp;(I think a whitelist removes the point of referrals,
         and I'll&amp;nbsp;greatly prefer a keyword-based black list) or some other technique.&lt;/li&gt;
      &lt;li&gt;
         I've avoided running a "private build" of dasBlog so far (as evidenced by my care
         in creating the &lt;a href="http://www.hanselman.com/blog/PermaLink.aspx?guid=99b2e3e9-5597-4883-a015-d77c3246a2a8"&gt;CAPTCHA
         solution without recompiling&lt;/a&gt;) and I'd to continue as such&lt;/li&gt;
   &lt;/ul&gt;
   &lt;li&gt;
      Clean the .xml files occasionally with a process&lt;/li&gt;
   &lt;ul&gt;
      &lt;li&gt;
         This is quick, easy, can be automated, and will work in the short term for me as I
         await dasBlog 1.7.&lt;/li&gt;
   &lt;/ul&gt;
&lt;/ul&gt;
&lt;p&gt;
   So, here was an opportunity to use the only dev stuff I have on my home machine, &lt;a href="http://lab.msdn.microsoft.com/express/vcsharp/default.aspx"&gt;Visual
   Studio C# 2005 Express&lt;/a&gt;.&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
   Here's what I did. Use at your own risk, back up your /content directory, and know
   that this will only&amp;nbsp;have to run on your "*.dayextra.xml" files from dasBlog.
   No error handling, no warrenty, but it worked for me. Enjoy.
&lt;/p&gt;
&lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt;
&lt;p&gt;
   &lt;strong&gt;Usage: TrackingFilter "c:\yourdasblogcontentdirectory"&lt;/strong&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p dir="ltr" style="MARGIN-RIGHT: 0px"&gt;
   &lt;a href="http://www.hanselman.com/blog/content/binary/TrackingFilter.zip"&gt;File Attachment:
   TrackingFilter.zip (9 KB)&lt;/a&gt;&amp;nbsp;(for VS.NET 2005, I don't know if it works in 2003) 
&lt;/p&gt;
&lt;p dir="ltr" style="MARGIN-RIGHT: 0px"&gt;
   &lt;font color="#ff0000"&gt;&lt;strong&gt;WARNING: &lt;/strong&gt;The words I put in the .config file
   are ; delimited and are &lt;em&gt;unquestionably offensive&lt;/em&gt;. Not only do they include
   most of&amp;nbsp;&lt;a href="http://www.erenkrantz.com/Humor/SevenDirtyWords.shtml"&gt;George
   Carlin's words&lt;/a&gt;&amp;nbsp;but they also include "bloglines" and "artima" because they
   don't provide a value in my referral list.&lt;/font&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=8c8cbf02-b25f-4170-9e68-110afdaa46f1"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=8c8cbf02-b25f-4170-9e68-110afdaa46f1</comments>
      <category>ASP.NET</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=1b228de5-b940-450b-b024-9751685431b0</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=1b228de5-b940-450b-b024-9751685431b0</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=1b228de5-b940-450b-b024-9751685431b0</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=1b228de5-b940-450b-b024-9751685431b0</wfw:commentRss>
      <slash:comments>0</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
      I spend a lot of time with the XmlSerializer (I personally dig it immensely, and I
      think too many people complain about it, but anyway) and while I put up <a href="http://www.hanselman.com/blog/PermaLink.aspx?guid=4185d5c5-17ab-4ed6-b934-e244b9895b4c">an
      article on how to debug directly into the generated assemblies</a>, I noticed that <a href="http://weblogs.asp.net/mnolton/archive/2004/12/01/273027.aspx">Mathew
      Nolton</a> has a <a href="http://www.cybral.com/solutions/tools.htm#XmlPrecompiler">GUI
      Front-End</a> to <a href="http://www.sellsbrothers.com/tools/#XmlSerializerPreCompiler">Chris's</a><a href="http://www.cybral.com/solutions/tools.htm#XmlPrecompiler">XmlSerializerPreCompiler</a>.
   </p>
        <p>
      The tool will check to see if a type can be serialized by the XmlSerializer and shows
      any compiler errors that happen behind the scenes. +1 for Useful, thanks <a href="http://www.sellsbrothers.com/">Chris</a> and <a href="http://weblogs.asp.net/mnolton/archive/2004/12/01/273027.aspx">Mathew</a>.
   </p>
        <img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=1b228de5-b940-450b-b024-9751685431b0" />
      </body>
      <title>GUI Front End to Chris Sells' XmlPreCompiler - For Debugging XmlSerialization Errors</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=1b228de5-b940-450b-b024-9751685431b0</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=1b228de5-b940-450b-b024-9751685431b0</link>
      <pubDate>Fri, 03 Dec 2004 22:56:32 GMT</pubDate>
      <description>&lt;p&gt;
   I spend a lot of time with the XmlSerializer (I personally dig it immensely, and I
   think too many people complain about it, but anyway) and while I put up &lt;a href="http://www.hanselman.com/blog/PermaLink.aspx?guid=4185d5c5-17ab-4ed6-b934-e244b9895b4c"&gt;an
   article on how to debug directly into the generated assemblies&lt;/a&gt;, I noticed that &lt;a href="http://weblogs.asp.net/mnolton/archive/2004/12/01/273027.aspx"&gt;Mathew
   Nolton&lt;/a&gt; has a &lt;a href="http://www.cybral.com/solutions/tools.htm#XmlPrecompiler"&gt;GUI
   Front-End&lt;/a&gt; to &lt;a href="http://www.sellsbrothers.com/tools/#XmlSerializerPreCompiler"&gt;Chris's&lt;/a&gt; &lt;a href="http://www.cybral.com/solutions/tools.htm#XmlPrecompiler"&gt;XmlSerializerPreCompiler&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
   The tool will check to see if a type can be serialized by the XmlSerializer and shows
   any compiler errors that happen behind the scenes. +1 for Useful, thanks &lt;a href="http://www.sellsbrothers.com/"&gt;Chris&lt;/a&gt; and &lt;a href="http://weblogs.asp.net/mnolton/archive/2004/12/01/273027.aspx"&gt;Mathew&lt;/a&gt;.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=1b228de5-b940-450b-b024-9751685431b0"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=1b228de5-b940-450b-b024-9751685431b0</comments>
      <category>ASP.NET</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=43e49ec8-1fa7-44c1-8177-42cd4fead8db</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=43e49ec8-1fa7-44c1-8177-42cd4fead8db</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=43e49ec8-1fa7-44c1-8177-42cd4fead8db</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=43e49ec8-1fa7-44c1-8177-42cd4fead8db</wfw:commentRss>
      <slash:comments>4</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
      A fellow emailed me wanting to screen scrape, er, ah, harvest a page that only
      displays the data he wants with a postback.
   </p>
        <p>
      Remember what an HTTP GET looks like <a href="http://www.blunck.info/iehttpheaders.html">under
      the covers</a>:
   </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <strong>GET /whatever/page.aspx?param1=value&amp;param2=value</strong>
          </p>
        </blockquote>
        <p>
      Note that the GET includes no HTTP Body. That's important. With a POST the 'DATA'
      moves from the QueryString into the HTTP Body, but you can still have stuff in the
      QueryString.
   </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <strong>POST /whatever/page.aspx?optionalotherparam1=value<br />
      Content-Type: application/x-www-form-urlencoded<br />
      Content-Length: 25<br />
      param1=value&amp;param2=value</strong>
          </p>
        </blockquote>
        <p>
      Note the Content-Type header and the Content-Length, those are important.
   </p>
        <p>
      A POST is just the verb for when you have an HTTP document. A GET implies you got
      nothing.
   </p>
        <p>
      So, in C#, here's a GET:
   </p>
        <p>
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">static</span>
            <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span> HttpGet(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span> URI) 
      <br />
      {<br />
         System.Net.WebRequest req <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">= </span>System.Net.WebRequest.Create(URI);<br />
         req.Proxy <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> System.Net.WebProxy(ProxyString, <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">true</span>);
      //true means no proxy<br />
         System.Net.WebResponse resp <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> req.GetResponse();<br />
         System.IO.StreamReader sr <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> System.IO.StreamReader(resp.GetResponseStream());<br />
         <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">return</span> sr.ReadToEnd().Trim();<br />
      }</span>
        </p>
        <p>
      Here's a POST:
   </p>
        <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
          <p>
            <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
              <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">public</span>
              <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">static</span>
              <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span> HttpPost(<span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span> URI, <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">string</span> Parameters) 
      <br />
      {<br />
         System.Net.WebRequest req <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> System.Net.WebRequest.Create(URI);<br />
         req.Proxy <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new</span> System.Net.WebProxy(ProxyString, <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">true</span>);<br /></span>
            <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">   //Add
      these, as we're doing a POST<br />
         req.ContentType <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"application/x-www-form-urlencoded"</span>;<br />
         req.Method <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4">"POST"</span>;<br />
         //We need to count how many bytes we're sending. Post'ed Faked
      Forms should be name=value&amp;<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">  
      byte</span> [] bytes <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> System.Text.Encoding.ASCII.GetBytes(Parameters);<br />
         req.ContentLength <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> bytes.Length;<br />
         System.IO.Stream os <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> req.GetRequestStream
      ();<br />
         os.Write (bytes, 0, bytes.Length); //Push it out there<br />
         os.Close ();<br />
         System.Net.WebResponse resp <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span> req.GetResponse();<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">  
      if</span> (resp== <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">null</span>) <span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">return</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">null</span>;<br />
         System.IO.StreamReader sr <span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">=</span><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">new </span>System.IO.StreamReader(resp.GetResponseStream());<br /><span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">  
      return</span> sr.ReadToEnd().Trim();<br />
      }<br /></span>
          </p>
        </span>
        <p>
      I could and should have put in more 'using' statements, but you get the gist. And,
      there are other ways to have done this with the BCL, but this is one.
   </p>
        <p>
      Now, how would you fake an HTTP PostBack? Use a tool like <a href="http://www.blunck.info/iehttpheaders.html">ieHttpHeaders</a> to
      watch what a real postback looks like, and well, fake it. :) Just hope they don't
      require unique/encrypted ViewState (via ViewStateUserKey or EnableViewStateMac) for
      that page, or you're out of luck.
   </p>
        <img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=43e49ec8-1fa7-44c1-8177-42cd4fead8db" />
      </body>
      <title>HTTP POSTs and HTTP GETs with WebClient and C# and Faking a PostBack</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=43e49ec8-1fa7-44c1-8177-42cd4fead8db</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=43e49ec8-1fa7-44c1-8177-42cd4fead8db</link>
      <pubDate>Fri, 03 Dec 2004 07:37:17 GMT</pubDate>
      <description>&lt;p&gt;
   A fellow emailed me wanting to screen scrape, er, ah, harvest&amp;nbsp;a page that only
   displays the data he wants with a postback.
&lt;/p&gt;
&lt;p&gt;
   Remember what an HTTP GET looks like &lt;a href="http://www.blunck.info/iehttpheaders.html"&gt;under
   the covers&lt;/a&gt;:
&lt;/p&gt;
&lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt;
&lt;p&gt;
   &lt;strong&gt;GET /whatever/page.aspx?param1=value&amp;amp;param2=value&lt;/strong&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
   Note that the GET includes no HTTP Body. That's important. With a POST the&amp;nbsp;'DATA'
   moves from the QueryString into the HTTP Body, but you can still have stuff in the
   QueryString.
&lt;/p&gt;
&lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt;
&lt;p&gt;
   &lt;strong&gt;POST /whatever/page.aspx?optionalotherparam1=value&lt;br /&gt;
   Content-Type: application/x-www-form-urlencoded&lt;br /&gt;
   Content-Length: 25&lt;br /&gt;
   param1=value&amp;amp;param2=value&lt;/strong&gt;
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
   Note the Content-Type header and the Content-Length, those are important.
&lt;/p&gt;
&lt;p&gt;
   A POST is just the verb for when you have an HTTP document. A GET implies you got
   nothing.
&lt;/p&gt;
&lt;p&gt;
   So, in C#, here's a GET:
&lt;/p&gt;
&lt;p&gt;
   &lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;static&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt; HttpGet(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt; URI) 
   &lt;br /&gt;
   {&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; System.Net.WebRequest req &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;= &lt;/span&gt;System.Net.WebRequest.Create(URI);&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; req.Proxy &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; System.Net.WebProxy(ProxyString, &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;true&lt;/span&gt;);
   //true means no proxy&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; System.Net.WebResponse resp &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; req.GetResponse();&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; System.IO.StreamReader sr &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; System.IO.StreamReader(resp.GetResponseStream());&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;return&lt;/span&gt; sr.ReadToEnd().Trim();&lt;br /&gt;
   }&lt;/span&gt;
&lt;/p&gt;
&lt;p&gt;
   Here's a POST:
&lt;/p&gt;
&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;
&lt;p&gt;
   &lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;public&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;static&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt; HttpPost(&lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt; URI, &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;string&lt;/span&gt; Parameters) 
   &lt;br /&gt;
   {&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; System.Net.WebRequest req &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; System.Net.WebRequest.Create(URI);&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; req.Proxy &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new&lt;/span&gt; System.Net.WebProxy(ProxyString, &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;true&lt;/span&gt;);&lt;br /&gt;
   &lt;/span&gt;&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;//Add
   these, as we're doing a&amp;nbsp;POST&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; req.ContentType &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"application/x-www-form-urlencoded"&lt;/span&gt;;&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; req.Method &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: #666666; FONT-FAMILY: Courier New; BACKGROUND-COLOR: #e4e4e4"&gt;"POST"&lt;/span&gt;;&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; //We need to count how many bytes we're&amp;nbsp;sending.&amp;nbsp;Post'ed Faked
   Forms should be name=value&amp;amp;&lt;br /&gt;
   &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;
   byte&lt;/span&gt; [] bytes &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; System.Text.Encoding.ASCII.GetBytes(Parameters);&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; req.ContentLength &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; bytes.Length;&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; System.IO.Stream os &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; req.GetRequestStream
   ();&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; os.Write (bytes, 0, bytes.Length); //Push&amp;nbsp;it out there&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; os.Close ();&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; System.Net.WebResponse resp &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; req.GetResponse();&lt;br /&gt;
   &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;
   if&lt;/span&gt; (resp== &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;null&lt;/span&gt;) &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;return&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;null&lt;/span&gt;;&lt;br /&gt;
   &amp;nbsp;&amp;nbsp; System.IO.StreamReader sr &lt;span style="FONT-SIZE: 11px; COLOR: red; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;=&lt;/span&gt; &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;new &lt;/span&gt;System.IO.StreamReader(resp.GetResponseStream());&lt;br /&gt;
   &lt;span style="FONT-SIZE: 11px; COLOR: blue; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&amp;nbsp;&amp;nbsp;
   return&lt;/span&gt; sr.ReadToEnd().Trim();&lt;br /&gt;
   }&lt;br /&gt;
&lt;/p&gt;
&lt;/span&gt;&gt;
&lt;p&gt;
   I could and should have put in more 'using' statements, but you get the gist. And,
   there are other ways to have done this with the BCL, but this is one.
&lt;/p&gt;
&lt;p&gt;
   Now, how would you fake an HTTP&amp;nbsp;PostBack? Use a tool like &lt;a href="http://www.blunck.info/iehttpheaders.html"&gt;ieHttpHeaders&lt;/a&gt; to
   watch what a real postback looks like, and well, fake it. :) Just hope they don't
   require unique/encrypted ViewState (via ViewStateUserKey or EnableViewStateMac) for
   that page, or you're out of luck.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=43e49ec8-1fa7-44c1-8177-42cd4fead8db"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=43e49ec8-1fa7-44c1-8177-42cd4fead8db</comments>
      <category>ASP.NET</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=228293b6-c0f0-4cb6-ba10-0c18e728be6d</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=228293b6-c0f0-4cb6-ba10-0c18e728be6d</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=228293b6-c0f0-4cb6-ba10-0c18e728be6d</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=228293b6-c0f0-4cb6-ba10-0c18e728be6d</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
      I've not been one to work the newsgroups, answering questions. I probably should.
      I'm more of a one on one person, and I tend to go the extra mile when folks (largely
      strangers) ask me technical questions. I've had email threads 10-deep with total strangers
      on technical questions, and only at the end do I say, "Um, do I know you?"
   </p>
        <p>
      I haven't <a href="http://scottonwriting.net/sowblog/posts/2594.aspx">done what Scott
      Mitchell wisely did</a> and setup a "Getting Help" policy, but I'm quickly getting
      there. I'll happily answer your question for $75 too, satisfaction guaranteed, and
      I'll blog the answer. I've done this hundreds of times for free. :)
   </p>
        <p>
      Anyway, the point of this post was this: People, for crying out loud, debug a few
      things before you ask for help. If you don't know how to debug, learn or ask someone
      to teach you.
   </p>
        <p>
      So, I present:
   </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <strong>
              <em>The Hanselman List of .NET Debugging Dos and Don'ts</em>
            </strong>
          </p>
          <p>
            <strong>Don't - </strong>Say "Hey, I got a NullReferenceException," what's the problem?<br /><strong>Do - </strong>Provide a Stack Trace/Dump with the line number it likely happened
      on.
   </p>
          <p>
            <strong>Don't - </strong>Get deep into your complicated program, find a bug and insist
      it's BillGs fault.<br /><strong>Do - </strong>Reproduce the bug in some simple test program and tell the world.
      Remember, 9/10 times it's you.
   </p>
          <p>
            <strong>Don't - </strong>Decide there's a problem if you don't know the preferred
      behavior.<br /><strong>Do - </strong>Always Assert your assumptions. If null can happen, check for
      it. BUT, if null <em>must never happen</em> it's time for a Debug.Assert
   </p>
          <p>
            <strong>Don't - </strong>Move code around blindly, somehow fix your bug, ignore it
      and keep coding. Programming by Coincidence! 
      <br /><strong>Do - </strong>Understand your program fully. Remember what <a href="http://pragmaticprogrammer.com/ppbook/extracts/coincidence.html">Andy
      and Dave say about lucky folks who step into minefields</a> and don't die. Just because
      you didn't die, doesn't mean there aren't mines!
   </p>
          <p>
            <strong>Don't - </strong>Reformat or "pave" something because you don't know what's
      wrong. If you get a spot on your carpet, fix the spot. Don't lay new carpet.<br /><strong>Do - </strong>Know enough about your environment to know what your program's
      dependencies are. If your registry settings can get boogered, Debug.Assert that you
      are getting good values from the registry.
   </p>
          <p>
            <strong>Don't </strong>- Get overly frustrated with Assembly loading/versioning/policy.
      At least the Assembly Loader follows clear, set, rules. 
      <br /><strong>Do </strong>- Make a folder called C:\FusionLogs, then go to the registry
      in HKLM:\Software\Microsoft\Fusion and make a DWORD value LogFailures=1 and string
      value LogPath=C:\FusionLogs. Every AppDomain that has a binding failure or weird redirect
      will get logged. Know: <em>What assembly you want, what they looked for, what you
      got. </em>Know where Assemblies are searched for.
   </p>
          <p>
            <strong>Don't - </strong>Avoid debugging. Debugging in .NET is easier than ever before.
      Remote debugging and AttachToProcess are gifts. Don't stop at a point in the call
      stack if you can keep going by finding PDBs.<br /><strong>Do - </strong>Keep your Source and PDBs in the same location. We keep ZIPs
      of every build's PDBs. Just today we dug up 9-month old PDBs and source (from CVS)
      to debug into some confusion. Not saving those PDBs would have screwed us. Create
      a Symbol Server.
   </p>
          <p>
            <strong>Don't </strong>- Limit yourself to the QuickWatch. Learn what VS.NET has to
      offer.<br /><strong>Do - </strong>Use the Immediate Window to test theories. Remember that you
      can perform Casts in the Watch Window. Remember that you can drag and drop variables
      into the Watch Window. Remember you have 4 Watch Windows, Autos, Locals, not to mention.
      Learn how to use Conditional Breakpoints!
   </p>
          <p>
            <strong>Don't</strong> - not debug something just because you can't figure out how
      to launch the process from the VS.NET Project Properties.<br /><strong>Do - </strong>Debug|Processes|Attach to attach to processes that have your
      DLL loaded. Use ProcExp from <a href="http://www.sysinternals.com/">SysInternals</a> as
      a better Task Manager to see .NET processes, as well as a system-wide DLL search.
      Who's got you loaded?
   </p>
        </blockquote>
        <img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=228293b6-c0f0-4cb6-ba10-0c18e728be6d" />
      </body>
      <title>Being a good .NET citizen means certain things...start with your debugging skills</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=228293b6-c0f0-4cb6-ba10-0c18e728be6d</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=228293b6-c0f0-4cb6-ba10-0c18e728be6d</link>
      <pubDate>Fri, 03 Dec 2004 07:10:09 GMT</pubDate>
      <description>&lt;p&gt;
   I've not been one to work the newsgroups, answering questions. I probably should.
   I'm more of a one on one person, and I tend to&amp;nbsp;go the extra mile when folks (largely
   strangers) ask me technical questions. I've had email threads 10-deep with total strangers
   on technical questions, and only at the end do I say, "Um, do I know you?"
&lt;/p&gt;
&lt;p&gt;
   I haven't &lt;a href="http://scottonwriting.net/sowblog/posts/2594.aspx"&gt;done what Scott
   Mitchell wisely did&lt;/a&gt;&amp;nbsp;and setup a "Getting Help" policy, but I'm quickly getting
   there. I'll happily answer your question for $75 too, satisfaction guaranteed, and
   I'll blog the answer. I've done this hundreds of times for free. :)
&lt;/p&gt;
&lt;p&gt;
   Anyway, the point of this post was this: People, for crying out loud, debug a few
   things before you ask for help. If you don't know how to debug, learn or ask someone
   to teach you.
&lt;/p&gt;
&lt;p&gt;
   So, I present:
&lt;/p&gt;
&lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt;
&lt;p&gt;
   &lt;strong&gt;&lt;em&gt;The Hanselman List of .NET Debugging Dos and Don'ts&lt;/em&gt;&lt;/strong&gt;
&lt;/p&gt;
&lt;p&gt;
   &lt;strong&gt;Don't - &lt;/strong&gt;Say "Hey, I got a NullReferenceException," what's the problem?&lt;br /&gt;
   &lt;strong&gt;Do - &lt;/strong&gt;Provide a Stack Trace/Dump with the line number it likely happened
   on.
&lt;/p&gt;
&lt;p&gt;
   &lt;strong&gt;Don't - &lt;/strong&gt;Get deep into your complicated program, find a bug and insist
   it's BillGs fault.&lt;br /&gt;
   &lt;strong&gt;Do - &lt;/strong&gt;Reproduce the bug in some simple test program and tell the world.
   Remember, 9/10 times it's you.
&lt;/p&gt;
&lt;p&gt;
   &lt;strong&gt;Don't - &lt;/strong&gt;Decide there's a problem if you don't know the preferred
   behavior.&lt;br /&gt;
   &lt;strong&gt;Do - &lt;/strong&gt;Always Assert your assumptions. If null can happen, check for
   it. BUT, if null &lt;em&gt;must never happen&lt;/em&gt;&amp;nbsp;it's time for a Debug.Assert
&lt;/p&gt;
&lt;p&gt;
   &lt;strong&gt;Don't - &lt;/strong&gt;Move code around blindly, somehow fix your bug, ignore it
   and keep coding. Programming by Coincidence! 
   &lt;br /&gt;
   &lt;strong&gt;Do - &lt;/strong&gt;Understand your program fully. Remember what &lt;a href="http://pragmaticprogrammer.com/ppbook/extracts/coincidence.html"&gt;Andy
   and Dave say about lucky folks who step into minefields&lt;/a&gt; and don't die. Just because
   you didn't die, doesn't mean there aren't mines!
&lt;/p&gt;
&lt;p&gt;
   &lt;strong&gt;Don't - &lt;/strong&gt;Reformat or "pave" something because you don't know what's
   wrong. If you get a spot on your carpet, fix the spot. Don't lay new carpet.&lt;br /&gt;
   &lt;strong&gt;Do - &lt;/strong&gt;Know enough about your environment to know what your program's
   dependencies are. If your registry settings can get boogered, Debug.Assert that you
   are getting good values from the registry.
&lt;/p&gt;
&lt;p&gt;
   &lt;strong&gt;Don't &lt;/strong&gt;- Get overly frustrated with Assembly loading/versioning/policy.
   At least the Assembly Loader follows clear, set, rules. 
   &lt;br /&gt;
   &lt;strong&gt;Do &lt;/strong&gt;- Make a folder called C:\FusionLogs, then go to the registry
   in HKLM:\Software\Microsoft\Fusion and make a DWORD value LogFailures=1 and string
   value LogPath=C:\FusionLogs. Every AppDomain that has a binding failure or weird redirect
   will get logged. Know: &lt;em&gt;What assembly you want, what they looked for, what you
   got. &lt;/em&gt;Know where Assemblies are searched for.
&lt;/p&gt;
&lt;p&gt;
   &lt;strong&gt;Don't - &lt;/strong&gt;Avoid debugging. Debugging in .NET is easier than ever before.
   Remote debugging and AttachToProcess are gifts. Don't stop at a point in the call
   stack if you can keep going by finding PDBs.&lt;br /&gt;
   &lt;strong&gt;Do - &lt;/strong&gt;Keep your Source and PDBs in the same location. We keep ZIPs
   of every build's PDBs. Just today we dug up 9-month old PDBs and source (from CVS)
   to debug into some confusion. Not saving those PDBs would have screwed us. Create
   a Symbol Server.
&lt;/p&gt;
&lt;p&gt;
   &lt;strong&gt;Don't &lt;/strong&gt;- Limit yourself to the QuickWatch. Learn what VS.NET has to
   offer.&lt;br /&gt;
   &lt;strong&gt;Do - &lt;/strong&gt;Use the Immediate Window to test theories. Remember that you
   can perform Casts in the Watch Window. Remember that you can drag and drop variables
   into the Watch Window. Remember you have 4 Watch Windows, Autos, Locals, not to mention.
   Learn how to use Conditional Breakpoints!
&lt;/p&gt;
&lt;p&gt;
   &lt;strong&gt;Don't&lt;/strong&gt; - not debug something just because you can't figure out how
   to launch the process from the VS.NET Project Properties.&lt;br /&gt;
   &lt;strong&gt;Do - &lt;/strong&gt;Debug|Processes|Attach to attach to processes that have your
   DLL loaded. Use ProcExp from &lt;a href="http://www.sysinternals.com/"&gt;SysInternals&lt;/a&gt;&amp;nbsp;as
   a better Task Manager to see .NET processes, as well as a system-wide DLL search.
   Who's got you loaded?
&lt;/p&gt;
&lt;/blockquote&gt;&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=228293b6-c0f0-4cb6-ba10-0c18e728be6d"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=228293b6-c0f0-4cb6-ba10-0c18e728be6d</comments>
      <category>ASP.NET</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=245d5d2c-73fa-400d-a894-bff747254f97</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=245d5d2c-73fa-400d-a894-bff747254f97</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=245d5d2c-73fa-400d-a894-bff747254f97</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=245d5d2c-73fa-400d-a894-bff747254f97</wfw:commentRss>
      <slash:comments>0</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
      It's 1:09am on Thursday, December 2nd 2004, and here's the view from my bedroom window.
      The house next door is burning and we share a wooden fence. Pretty exciting stuff!
      Fortunately, I'm not too worried, I'm in a <a href="http://www.hanselman.com/blog/content/binary/P0005257_20_28Small_29.jpg">family</a> of <a href="http://www.hanselman.com/blog/content/binary/P0005260_20_28Small_29.jpg">fire-fighters</a>.
   </p>
        <p>
          <a href="http://www.hanselman.com/blog/content/binary/CIMG2539_20_28Small_29.JPG">
            <img height="240" alt="CIMG2539 (Small)" src="http://www.hanselman.com/blog/content/binary/CIMG2539_20_28Small_29_small1.jpg" width="320" border="0" />
          </a> <a href="http://www.hanselman.com/blog/content/binary/CIMG2546_20_28Small_29.JPG"><img height="240" alt="CIMG2546 (Small)" src="http://www.hanselman.com/blog/content/binary/CIMG2546_20_28Small_29_small1.jpg" width="320" border="0" /></a></p>
        <p>
          <a href="http://www.hanselman.com/blog/content/binary/CIMG2547_20_28Small_29.JPG">
            <img height="240" alt="CIMG2547 (Small)" src="http://www.hanselman.com/blog/content/binary/CIMG2547_20_28Small_29_small.jpg" width="320" border="0" />
          </a> <a href="http://www.hanselman.com/blog/content/binary/CIMG2540_20_28Small_29.JPG"><img height="240" alt="CIMG2540 (Small)" src="http://www.hanselman.com/blog/content/binary/CIMG2540_20_28Small_29_small.jpg" width="320" border="0" /></a></p>
        <p>
      P.S. For those of you not in the U.S., most, if not all, residential housing (especially
      in the Suburban Western U.S.) is made of wood and quite flammable. My wife's still
      not used to this fact, and her family isn't impressed that our family fights fires.
      :)
   </p>
        <img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=245d5d2c-73fa-400d-a894-bff747254f97" />
      </body>
      <title>FireBlogging - The View From My House</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=245d5d2c-73fa-400d-a894-bff747254f97</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=245d5d2c-73fa-400d-a894-bff747254f97</link>
      <pubDate>Thu, 02 Dec 2004 09:10:27 GMT</pubDate>
      <description>&lt;p&gt;
   It's 1:09am on Thursday, December 2nd 2004, and here's the view from my bedroom window.
   The house next door is burning and we share a wooden fence. Pretty exciting stuff!
   Fortunately, I'm not too worried, I'm in a &lt;a href="http://www.hanselman.com/blog/content/binary/P0005257_20_28Small_29.jpg"&gt;family&lt;/a&gt;&amp;nbsp;of &lt;a href="http://www.hanselman.com/blog/content/binary/P0005260_20_28Small_29.jpg"&gt;fire-fighters&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
   &lt;a href="http://www.hanselman.com/blog/content/binary/CIMG2539_20_28Small_29.JPG"&gt;&lt;img height="240" alt="CIMG2539 (Small)" src="http://www.hanselman.com/blog/content/binary/CIMG2539_20_28Small_29_small1.jpg" width="320" border="0" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://www.hanselman.com/blog/content/binary/CIMG2546_20_28Small_29.JPG"&gt;&lt;img height="240" alt="CIMG2546 (Small)" src="http://www.hanselman.com/blog/content/binary/CIMG2546_20_28Small_29_small1.jpg" width="320" border="0" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
   &lt;a href="http://www.hanselman.com/blog/content/binary/CIMG2547_20_28Small_29.JPG"&gt;&lt;img height="240" alt="CIMG2547 (Small)" src="http://www.hanselman.com/blog/content/binary/CIMG2547_20_28Small_29_small.jpg" width="320" border="0" /&gt;&lt;/a&gt;&amp;nbsp;&lt;a href="http://www.hanselman.com/blog/content/binary/CIMG2540_20_28Small_29.JPG"&gt;&lt;img height="240" alt="CIMG2540 (Small)" src="http://www.hanselman.com/blog/content/binary/CIMG2540_20_28Small_29_small.jpg" width="320" border="0" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
   P.S. For those of you not in the U.S., most, if not all, residential housing (especially
   in the Suburban Western U.S.) is made of wood and quite flammable. My wife's still
   not used to this fact, and her family isn't impressed that our family fights fires.
   :)
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=245d5d2c-73fa-400d-a894-bff747254f97"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=245d5d2c-73fa-400d-a894-bff747254f97</comments>
      <category>Musings</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=5077d050-ead4-491b-9df1-be02a030e03a</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=5077d050-ead4-491b-9df1-be02a030e03a</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=5077d050-ead4-491b-9df1-be02a030e03a</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=5077d050-ead4-491b-9df1-be02a030e03a</wfw:commentRss>
      <slash:comments>9</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
      Here's a great little free util that <a href="http://www.shahine.com/omar/PermaLink,guid,0b32ead3-5f9b-4b7a-99de-44055b8b6e5a.aspx">Omar</a> has
      found.  I used to move the plugin's manually to speed things up, but <a href="http://www.shahine.com/omar/PermaLink,guid,0b32ead3-5f9b-4b7a-99de-44055b8b6e5a.aspx">PDF
      Speedup</a> makes me NOT DREAD opening a PDF anymore. BTW, does Acrobat
      6 suck LOTS more than Acrobat 5? I HATE the new Find Dialog.
   </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <em>I have previously written about how darn slow Adobe Acrobat 6 is when launching.
      I don't understand why Acrobat is so darn annoying. Here are some things I don't care
      for:<br /><br />
      * Don't create a “My eBooks“ folder in My Documents when I have nothing
      to put there.<br />
      * Don't load 500 plugins when none of them are necessary to view a PDF<br />
      * Don't place shortcuts for some lame Internet Printing thingy in my Start Menu (I
      loathe Start Menu Advertising)<br />
      * Do install a PDF IFilter so that indexing products like Lookout can index PDFs w/o
      installing it seperatley<br />
      * Don't load PDFs in IE because it is god awful slow<br />
      * Don't make copy and paste so freaking hard<br />
      * Don't ask me to install other Adobe software when I boot Acrobat<br />
      * Don't create an updater (6.0.2) that creates an additional entry in my add/remove
      programs<br /><br />
      If you want to fix most of these things, PDF SpeedUp is a free application that should
      come bundled with Acrobat. It's a must have piece of software to make Acrobat behave
      (as much as you can anyway). </em>[<a href="http://www.shahine.com/omar/">shahine.com/omar/</a>]<br /></p>
        </blockquote>
        <img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=5077d050-ead4-491b-9df1-be02a030e03a" />
      </body>
      <title>Adobe PDF Reader slower than Molasses? Speed up Acrobat Reader 10x+</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=5077d050-ead4-491b-9df1-be02a030e03a</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=5077d050-ead4-491b-9df1-be02a030e03a</link>
      <pubDate>Thu, 02 Dec 2004 05:29:16 GMT</pubDate>
      <description>&lt;p&gt;
   Here's a great little free util that &lt;a href="http://www.shahine.com/omar/PermaLink,guid,0b32ead3-5f9b-4b7a-99de-44055b8b6e5a.aspx"&gt;Omar&lt;/a&gt; has
   found.&amp;nbsp; I used to move the plugin's manually to speed things up, but &lt;a href="http://www.shahine.com/omar/PermaLink,guid,0b32ead3-5f9b-4b7a-99de-44055b8b6e5a.aspx"&gt;PDF
   Speedup&lt;/a&gt;&amp;nbsp;makes me&amp;nbsp;NOT DREAD opening a PDF anymore. BTW, does Acrobat
   6 suck LOTS more than Acrobat 5? I HATE the new Find Dialog.
&lt;/p&gt;
&lt;blockquote dir=ltr style="MARGIN-RIGHT: 0px"&gt; 
&lt;p&gt;
   &lt;em&gt;I have previously written about how darn slow Adobe Acrobat 6 is when launching.
   I don't understand why Acrobat is so darn annoying. Here are some things I don't care
   for:&lt;br&gt;
   &lt;br&gt;
   * Don't create a &amp;#8220;My eBooks&amp;#8220; folder in My Documents when I have nothing
   to put there.&lt;br&gt;
   * Don't load 500 plugins when none of them are necessary to view a PDF&lt;br&gt;
   * Don't place shortcuts for some lame Internet Printing thingy in my Start Menu (I
   loathe Start Menu Advertising)&lt;br&gt;
   * Do install a PDF IFilter so that indexing products like Lookout can index PDFs w/o
   installing it seperatley&lt;br&gt;
   * Don't load PDFs in IE because it is god awful slow&lt;br&gt;
   * Don't make copy and paste so freaking hard&lt;br&gt;
   * Don't ask me to install other Adobe software when I boot Acrobat&lt;br&gt;
   * Don't create an updater (6.0.2) that creates an additional entry in my add/remove
   programs&lt;br&gt;
   &lt;br&gt;
   If you want to fix most of these things, PDF SpeedUp is a free application that should
   come bundled with Acrobat. It's a must have piece of software to make Acrobat behave
   (as much as you can anyway). &lt;/em&gt;[&lt;a href="http://www.shahine.com/omar/"&gt;shahine.com/omar/&lt;/a&gt;]&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=5077d050-ead4-491b-9df1-be02a030e03a"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=5077d050-ead4-491b-9df1-be02a030e03a</comments>
      <category>Musings</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=944a5284-6b8d-4366-81e8-2e241401e1b3</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=944a5284-6b8d-4366-81e8-2e241401e1b3</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=944a5284-6b8d-4366-81e8-2e241401e1b3</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=944a5284-6b8d-4366-81e8-2e241401e1b3</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
      There's a lot of info out there on how to cobble together NUnit Unit Testing of ASP.NET
      Pages and assorted goo. <a href="http://nunitasp.sourceforge.net/">NUnitASP</a> is
      a nice class library to facilitate this kind of testing, but it doesn't solve a few
      problems:
   </p>
        <ul>
          <li>
         Do you have/want a Web Server on your Test/Build machine?</li>
          <li>
         How do you get your Test Pages and such over to the Web Server? Just automatically
         copy them?</li>
          <li>
         Are your Test cases self-contained? That is, do they require external files and other
         stuff to be carried along with them?</li>
        </ul>
        <p>
      I have a need to test a number of utility classes, base classes for System.Web.UI.Page
      and other miscellany and I'd like the tests to be entirely self contained and runnable
      only with NUnit as a requirement.
   </p>
        <p>
      So, here's a small solution we use at Corillian. I use <a href="http://asp.net/Projects/Cassini/Download/download.aspx?tabindex=0&amp;tabid=1">Cassini</a>,
      the tiny ASP.NET Web Server that brokers HTTP Requests to System.Web.Hosting
      and the ASP.NET Page Renderer. You may know Cassini as the precursor to the Visual
      Developer Web Server from Visual Studio "Whidbey" 2005. Cassini usually comes with
      two parts, CassiniWebServer.exe and Cassini.dll.  However, I don't want to launch
      a executables, so I'll just refer to Cassini.dll as that is the main engine.
   </p>
        <div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 10pt; BACKGROUND: #ffffff; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: #000000; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Courier New">
          <p style="MARGIN: 0px">
            <span style="COLOR: #0000ff">using</span>
            <span> Cassini;</span>
          </p>
          <p style="MARGIN: 0px">
          
      </p>
          <p style="MARGIN: 0px">
            <span>    [TestFixture]</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #0000ff">public</span>
            <span style="COLOR: #0000ff"> class</span>
            <span> WebTests</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    {</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        </span>
            <span style="COLOR: #0000ff">private</span>
            <span> Server
         webServer;</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        </span>
            <span style="COLOR: #0000ff">private</span>
            <span style="COLOR: #0000ff"> readonly</span>
            <span style="COLOR: #0000ff"> int</span>
            <span> webServerPort
         = 8085;</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        </span>
            <span style="COLOR: #0000ff">private</span>
            <span style="COLOR: #0000ff"> readonly</span>
            <span style="COLOR: #0000ff"> string</span>
            <span> webServerVDir
         = "/";</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        </span>
            <span style="COLOR: #0000ff">private</span>
            <span style="COLOR: #0000ff"> string</span>
            <span> tempPath
         = AppDomain.CurrentDomain.BaseDirectory;</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        </span>
            <span style="COLOR: #0000ff">private</span>
            <span style="COLOR: #0000ff"> string</span>
            <span> tempBinPath
         = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"bin");</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        </span>
            <span style="COLOR: #0000ff">private</span>
            <span style="COLOR: #0000ff"> string</span>
            <span> webServerUrl; </span>
            <span style="COLOR: #008000">//built
         in Setup</span>
          </p>
        </div>
        <!--EndFragment-->
        <p>
      Cassini is the 'private Server webServer' in the code above. I'm using a fairly random
      port, but you could certainly scan for an open port if you like. Note that I'm building
      a /bin folder, as Cassini's own ASP.NET Hostingn AppDomain will look for DLLs to load
      in /bin.
   </p>
        <p>
      Cassini starts up another AppDomain, and that AppDomain then loads Cassini.dll AGAIN,
      except the new AppDomain has a different search path that includes /bin, so it won't
      find Cassini.dll in the current directory. Usually this problem is solved by putting
      Cassini.dll in the GAC, but I want this test to be self-contained, and since I'll
      need my other DLLs in /bin anyway...
   </p>
        <div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 10pt; BACKGROUND: #ffffff; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: #000000; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Courier New">
          <p style="MARGIN: 0px">
            <span>[TestFixtureSetUp]</span>
          </p>
          <p style="MARGIN: 0px">
            <span style="COLOR: #0000ff">public</span>
            <span style="COLOR: #0000ff"> void</span>
            <span> Setup()</span>
          </p>
          <p style="MARGIN: 0px">
            <span>{</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #008000">//Extract the web.config
         and test cases (case sensitive!)</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    ExtractResource("web.config",tempPath);</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    ExtractResource("test1.aspx",tempPath);</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    ExtractResource("test2.aspx",tempPath);</span>
          </p>
          <p style="MARGIN: 0px">
          
      </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #008000">//NOTE: Cassini is going
         to load itself AGAIN into another AppDomain,</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #008000">// and will be getting
         it's Assembliesfrom the BIN, including another copy of itself!</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #008000">// Therefore we need
         to do this step FIRST because I've removed Cassini from the GAC</span>
          </p>
          <p style="MARGIN: 0px">
          
      </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #008000">//Copy our assemblies
         down into the web server's BIN folder</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    Directory.CreateDirectory(tempBinPath);</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #0000ff">foreach</span>
            <span>(</span>
            <span style="COLOR: #0000ff">string</span>
            <span> file </span>
            <span style="COLOR: #0000ff">in</span>
            <span> Directory.GetFiles(tempPath,"*.dll"))</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    {</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        </span>
            <span style="COLOR: #0000ff">string</span>
            <span> newFile
         = Path.Combine(tempBinPath,Path.GetFileName(file));</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        </span>
            <span style="COLOR: #0000ff">if</span>
            <span> (File.Exists(newFile)){File.Delete(newFile);}</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        File.Copy(file,newFile);</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    }</span>
          </p>
          <p style="MARGIN: 0px">
          
      </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #008000">//Start the internal
         Web Server</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    webServer = </span>
            <span style="COLOR: #0000ff">new</span>
            <span> Server(webServerPort,webServerVDir,tempPath);</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    webServerUrl = String.Format("http://localhost:{0}{1}",webServerPort,webServerVDir);</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    webServer.Start();</span>
          </p>
          <p style="MARGIN: 0px">
          
      </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #008000">//Let everyone know</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    Debug.WriteLine(String.Format("Web Server started on port
         {0} with VDir {1} in physical directory {2}",webServerPort,webServerVDir,tempPath));</span>
          </p>
          <p style="MARGIN: 0px">
            <span>}</span>
          </p>
        </div>
        <!--EndFragment-->
        <p>
      A couple of important things to note here. 
   </p>
        <ul>
          <li>
         This method is marked [TestFixtureSetup] rather than [Setup] as we want it to run
         only once for this whole Assembly, not once per test.</li>
          <li>
         We're copying all the DLLs in the current directory down to /bin for Cassini's use
         during the test, but we'll delete them in [TestFixtureTearDown] after Cassini's AppDomain.Unload.</li>
          <li>
         We build webServerUrl and start Cassini (remember, it's the "webServer" variable).</li>
          <li>
         At this point we are listing on <a href="http://localhost:8085/">http://localhost:8085/</a></li>
        </ul>
        <p>
      Additionally, I've snuck a new method in, ExtractResource(). This takes the name of
      an Embedded Resource (one that is INSIDE our test assembly) and puts it into a directory.
      In this case, I'm using the current AppDomain's directory, but you could certainly
      use Path.GetTempPath() if you like.
   </p>
        <div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 10pt; BACKGROUND: #ffffff; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: #000000; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Courier New">
          <p style="MARGIN: 0px">
            <span style="COLOR: #0000ff">private</span>
            <span> StringCollection extractedFilesToCleanup
         = </span>
            <span style="COLOR: #0000ff">new</span>
            <span> StringCollection();</span>
          </p>
          <p style="MARGIN: 0px">
            <span style="COLOR: #0000ff">private</span>
            <span style="COLOR: #0000ff"> string</span>
            <span> ExtractResource(</span>
            <span style="COLOR: #0000ff">string</span>
            <span> filename, </span>
            <span style="COLOR: #0000ff">string</span>
            <span> directory)</span>
          </p>
          <p style="MARGIN: 0px">
            <span>{</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    Assembly a = Assembly.GetExecutingAssembly();</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #0000ff">string</span>
            <span> filePath
         = </span>
            <span style="COLOR: #0000ff">null</span>
            <span>;</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #0000ff">string</span>
            <span> path
         = </span>
            <span style="COLOR: #0000ff">null</span>
            <span>;</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #0000ff">using</span>
            <span>(Stream
         stream = a.GetManifestResourceStream("Corillian.Voyager.Web.Test." + filename))</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    {</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        filePath = Path.Combine(directory,filename);</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        path = filePath;</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        </span>
            <span style="COLOR: #0000ff">using</span>
            <span>(StreamWriter
         outfile = File.CreateText(filePath))</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        {</span>
          </p>
          <p style="MARGIN: 0px">
            <span>            </span>
            <span style="COLOR: #0000ff">using</span>
            <span> (StreamReader
         infile = </span>
            <span style="COLOR: #0000ff">new</span>
            <span> StreamReader(stream))</span>
          </p>
          <p style="MARGIN: 0px">
            <span>            {</span>
          </p>
          <p style="MARGIN: 0px">
            <span>               
         outfile.Write(infile.ReadToEnd());    </span>
          </p>
          <p style="MARGIN: 0px">
            <span>            }</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        }</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    }</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    extractedFilesToCleanup.Add(filePath);</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #0000ff">return</span>
            <span> filePath;</span>
          </p>
          <p style="MARGIN: 0px">
            <span>}</span>
          </p>
        </div>
        <p>
      The ExtractResource method takes a filename and directory (and could, if you like,
      take a namespace, although I've hardcoded mine) and pulls a file as a Stream of bytes
      that was embedded as a resource in our Assembly and puts it into a directory. Hence
      the name, ExtractResource(). There is a StringCollection called extractedFilesToCleanup
      that keeps track of all the files we'll want to delete at the end of these tests,
      in [TestFixtureTearDown].
   </p>
        <p>
      At this point, I've got a web.config (which was important to my tests, and will be
      looked at by Cassini/System.Web.Hosting) and a test1.aspx and test2.aspx in my current
      directory. The Cassini Web Server is started up and listing on port 8085 for HttpRequests.
      I also turned Page Tracing on in the web.config which will allow me to make certain
      Assertions about what kinds of code were called by the Page and helper classes within
      the Cassini ASP.NET context.
   </p>
        <p>
      I'll add a helper method to create HttpRequests and return the response as a string:
   </p>
        <div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 10pt; BACKGROUND: #ffffff; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: #000000; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Courier New">
          <p style="MARGIN: 0px">
            <span style="COLOR: #0000ff">private</span>
            <span style="COLOR: #0000ff"> string</span>
            <span> GetPage(</span>
            <span style="COLOR: #0000ff">string</span>
            <span> page)</span>
          </p>
          <p style="MARGIN: 0px">
            <span>{</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    WebClient client = </span>
            <span style="COLOR: #0000ff">new</span>
            <span> WebClient();</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #0000ff">string</span>
            <span> url
         = </span>
            <span style="COLOR: #0000ff">new</span>
            <span> Uri(</span>
            <span style="COLOR: #0000ff">new</span>
            <span> Uri(webServerUrl),page).ToString();</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #0000ff">using</span>
            <span> (StreamReader
         reader = </span>
            <span style="COLOR: #0000ff">new</span>
            <span> StreamReader(client.OpenRead(url)))</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    {</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        </span>
            <span style="COLOR: #0000ff">string</span>
            <span> result
         = reader.ReadToEnd();</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        </span>
            <span style="COLOR: #0000ff">return</span>
            <span> result;</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    }</span>
          </p>
          <p style="MARGIN: 0px">
            <span>}</span>
          </p>
        </div>
        <!--EndFragment-->
        <p>
      Now I can write some tests! My tests need to test things like the overridden behavior
      of custom BasePages (derived from System.Web.UI.Page) as well as some helper functions
      that require (to be TRULY tested) an HttpContext. However, I don't want the hassle
      of a CodeBehind or a lot of other files, and certainly not the effort of a whole
      separate test project, so I'll make my ASPX pages self contained using &lt;%
      @Assembly %&gt; directives. So, for example: 
   </p>
        <div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 10pt; BACKGROUND: #ffffff; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: #000000; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Courier New">
          <span>
            <p>
              <font color="#ff0000">
                <strong>&lt;%@ Assembly Name="Corillian.Voyager.Web.Common"
         %&gt;</strong>
                <br />
              </font>&lt;%@ Page Language="C#" <strong><font color="#ff0000">Inherits="Corillian.Voyager.Web.Common.SharedBasePage" </font></strong>%&gt;<br />
         &lt;script runat="server"&gt;<br />
             public void Page_Load(object sender, EventArgs e )<br />
             {<br />
                 Label1.Text = "Hello";<br />
             }<br />
         &lt;/script&gt;<br />
         &lt;html&gt;<br />
           &lt;body&gt;<br />
             &lt;form runat="server"&gt;<br />
                 &lt;p&gt;<br />
                     &lt;asp:Label id="Label1"
         runat="server"&gt;Label<br />
                     &lt;/asp:Label&gt;<br />
                 &lt;/p&gt;<br />
             &lt;/form&gt;<br />
           &lt;/body&gt;<br />
         &lt;/html&gt;<br /></p>
          </span>
        </div>
        <!--EndFragment-->
        <p>
      A test to determine if this page executed successfully might look like:
   </p>
        <div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 10pt; BACKGROUND: #ffffff; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: #000000; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Courier New">
          <p style="MARGIN: 0px">
            <span>[Test]</span>
          </p>
          <p style="MARGIN: 0px">
            <span style="COLOR: #0000ff">public</span>
            <span style="COLOR: #0000ff"> void</span>
            <span> BasicSmokeTestOfWebServer()</span>
          </p>
          <p style="MARGIN: 0px">
            <span>{</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #0000ff">string</span>
            <span> result
         = GetPage("test1.aspx");</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    Assert.IsTrue(result.IndexOf("Hello") != -1,"Basic smoke
         test of test1.aspx didn't find 'Hello' in response!");</span>
          </p>
          <p style="MARGIN: 0px">
            <span>}</span>
          </p>
        </div>
        <p>
          <!--EndFragment-->You could easily expand your tests to include NUnitASP, or
      continue to use WebClient with specific HttpHeaders like accept-language or user-agent.
      One of our QA guys uses NUnit to automate the IE WebServer Control, the
      manipulates the DHTML DOM to make Assertions.
   </p>
        <p>
      Finally, my cleanup code is simple, deleting all the files we extracted as well as
      toasting the /bin folder.
   </p>
        <div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 10pt; BACKGROUND: #ffffff; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: #000000; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Courier New">
          <p style="MARGIN: 0px">
            <span>[TestFixtureTearDown]</span>
          </p>
          <p style="MARGIN: 0px">
            <span style="COLOR: #0000ff">public</span>
            <span style="COLOR: #0000ff"> void</span>
            <span> TearDown()</span>
          </p>
          <p style="MARGIN: 0px">
            <span>{</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #0000ff">try</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    {</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        </span>
            <span style="COLOR: #0000ff">if</span>
            <span> (webServer
         != </span>
            <span style="COLOR: #0000ff">null</span>
            <span>)</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        {</span>
          </p>
          <p style="MARGIN: 0px">
            <span>            webServer.Stop();</span>
          </p>
          <p style="MARGIN: 0px">
            <span>            webServer = </span>
            <span style="COLOR: #0000ff">null</span>
            <span>;</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        }</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        CleanupResources();</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        Directory.Delete(tempBinPath,</span>
            <span style="COLOR: #0000ff">true</span>
            <span>);</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    }</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #0000ff">catch</span>
            <span>{}</span>
          </p>
          <p style="MARGIN: 0px">
            <span>}</span>
          </p>
          <p style="MARGIN: 0px">
          
      </p>
          <p style="MARGIN: 0px">
            <span style="COLOR: #0000ff">private</span>
            <span style="COLOR: #0000ff"> void</span>
            <span> CleanupResources()</span>
          </p>
          <p style="MARGIN: 0px">
            <span>{</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #0000ff">try</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    {</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        </span>
            <span style="COLOR: #0000ff">foreach</span>
            <span>(</span>
            <span style="COLOR: #0000ff">string</span>
            <span> file </span>
            <span style="COLOR: #0000ff">in</span>
            <span> extractedFilesToCleanup)</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        {</span>
          </p>
          <p style="MARGIN: 0px">
            <span>            File.Delete(file);</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        }</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    }</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    </span>
            <span style="COLOR: #0000ff">catch</span>
            <span> (Exception
         ex)</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    {</span>
          </p>
          <p style="MARGIN: 0px">
            <span>        Debug.WriteLine(ex.ToString());</span>
          </p>
          <p style="MARGIN: 0px">
            <span>    }</span>
          </p>
          <p style="MARGIN: 0px">
            <span>}</span>
          </p>
        </div>
        <!--EndFragment-->
        <p>
      Now the WebServer, Test Cases and Test are nicely self-contained and can be moved
      to the CruiseControl.NET Continuous Integration Build Server. 
   </p>
        <p>
      Enjoy. I did.
   </p>
        <img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=944a5284-6b8d-4366-81e8-2e241401e1b3" />
      </body>
      <title>NUnit Unit Testing of ASP.NET Pages, Base Classes, Controls and other widgetry using Cassini (ASP.NET Web Matrix/Visual Studio Web Developer)</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=944a5284-6b8d-4366-81e8-2e241401e1b3</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=944a5284-6b8d-4366-81e8-2e241401e1b3</link>
      <pubDate>Wed, 01 Dec 2004 01:44:16 GMT</pubDate>
      <description>&lt;p&gt;
   There's a lot of info out there on how to cobble together NUnit Unit Testing of ASP.NET
   Pages and assorted goo. &lt;a href="http://nunitasp.sourceforge.net/"&gt;NUnitASP&lt;/a&gt; is
   a nice class library to facilitate this kind of testing, but it doesn't solve a few
   problems:
&lt;/p&gt;
&lt;ul&gt;
   &lt;li&gt;
      Do you have/want a Web Server on your Test/Build machine?&lt;/li&gt;
   &lt;li&gt;
      How do you get your Test Pages and such over to the Web Server? Just automatically
      copy them?&lt;/li&gt;
   &lt;li&gt;
      Are your Test cases self-contained? That is, do they require external files and other
      stuff to be carried along with them?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
   I have a need to test a number of utility classes, base classes for System.Web.UI.Page
   and other miscellany and I'd like the tests to be entirely self contained and runnable
   only with NUnit as a requirement.
&lt;/p&gt;
&lt;p&gt;
   So, here's a small solution we use at Corillian. I use &lt;a href="http://asp.net/Projects/Cassini/Download/download.aspx?tabindex=0&amp;amp;tabid=1"&gt;Cassini&lt;/a&gt;,
   the tiny ASP.NET&amp;nbsp;Web Server that brokers HTTP Requests to System.Web.Hosting
   and the ASP.NET Page Renderer. You may know Cassini as the precursor to the Visual
   Developer Web Server from Visual Studio "Whidbey" 2005. Cassini usually comes with
   two parts, CassiniWebServer.exe and Cassini.dll.&amp;nbsp; However, I don't want to launch
   a executables, so I'll just refer to Cassini.dll as that is the main engine.
&lt;/p&gt;
&lt;div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 10pt; BACKGROUND: #ffffff; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: #000000; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Courier New"&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span style="COLOR: #0000ff"&gt;using&lt;/span&gt;&lt;span&gt; Cassini;&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &amp;nbsp;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [TestFixture]&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;public&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt; class&lt;/span&gt;&lt;span&gt; WebTests&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;private&lt;/span&gt;&lt;span&gt; Server
      webServer;&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;private&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt; readonly&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt; int&lt;/span&gt;&lt;span&gt; webServerPort
      = 8085;&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;private&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt; readonly&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt; string&lt;/span&gt;&lt;span&gt; webServerVDir
      = "/";&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;private&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt; string&lt;/span&gt;&lt;span&gt; tempPath
      = AppDomain.CurrentDomain.BaseDirectory;&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;private&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt; string&lt;/span&gt;&lt;span&gt; tempBinPath
      = Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"bin");&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;private&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt; string&lt;/span&gt;&lt;span&gt; webServerUrl; &lt;/span&gt;&lt;span style="COLOR: #008000"&gt;//built
      in Setup&lt;/span&gt;
   &lt;/p&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
   Cassini is the 'private Server webServer' in the code above. I'm using a fairly random
   port, but you could certainly scan for an open port if you like. Note that I'm building
   a /bin folder, as Cassini's own ASP.NET Hostingn AppDomain will look for DLLs to load
   in /bin.
&lt;/p&gt;
&lt;p&gt;
   Cassini starts up another AppDomain, and that AppDomain then loads Cassini.dll AGAIN,
   except the new AppDomain has a different search path that includes /bin, so it won't
   find Cassini.dll in the current directory. Usually this problem is solved by putting
   Cassini.dll in the GAC, but I want this test to be self-contained, and since I'll
   need my other DLLs in /bin anyway...
&lt;/p&gt;
&lt;div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 10pt; BACKGROUND: #ffffff; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: #000000; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Courier New"&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;[TestFixtureSetUp]&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span style="COLOR: #0000ff"&gt;public&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt; void&lt;/span&gt;&lt;span&gt; Setup()&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;{&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #008000"&gt;//Extract the web.config
      and test cases (case sensitive!)&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ExtractResource("web.config",tempPath);&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ExtractResource("test1.aspx",tempPath);&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ExtractResource("test2.aspx",tempPath);&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &amp;nbsp;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #008000"&gt;//NOTE: Cassini is going
      to load itself AGAIN into another AppDomain,&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #008000"&gt;// and will be getting
      it's Assembliesfrom the BIN, including another copy of itself!&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #008000"&gt;// Therefore we need
      to do this step FIRST because I've removed Cassini from the GAC&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &amp;nbsp;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #008000"&gt;//Copy our assemblies
      down into the web server's BIN folder&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Directory.CreateDirectory(tempBinPath);&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;foreach&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;string&lt;/span&gt;&lt;span&gt; file &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;in&lt;/span&gt;&lt;span&gt; Directory.GetFiles(tempPath,"*.dll"))&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;string&lt;/span&gt;&lt;span&gt; newFile
      = Path.Combine(tempBinPath,Path.GetFileName(file));&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;if&lt;/span&gt;&lt;span&gt; (File.Exists(newFile)){File.Delete(newFile);}&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; File.Copy(file,newFile);&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &amp;nbsp;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #008000"&gt;//Start the internal
      Web Server&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; webServer = &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;new&lt;/span&gt;&lt;span&gt; Server(webServerPort,webServerVDir,tempPath);&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; webServerUrl = String.Format("http://localhost:{0}{1}",webServerPort,webServerVDir);&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; webServer.Start();&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &amp;nbsp;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #008000"&gt;//Let everyone know&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Debug.WriteLine(String.Format("Web Server started on port
      {0} with VDir {1} in physical directory {2}",webServerPort,webServerVDir,tempPath));&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;}&lt;/span&gt;
   &lt;/p&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
   A couple of important things to note here.&amp;nbsp;
&lt;/p&gt;
&lt;ul&gt;
   &lt;li&gt;
      This method is marked [TestFixtureSetup] rather than [Setup] as we want it to run
      only once for this whole Assembly, not once per test.&lt;/li&gt;
   &lt;li&gt;
      We're copying all the DLLs in the current directory down to /bin for Cassini's use
      during the test, but we'll delete them in [TestFixtureTearDown] after Cassini's AppDomain.Unload.&lt;/li&gt;
   &lt;li&gt;
      We build webServerUrl and start Cassini (remember, it's the "webServer" variable).&lt;/li&gt;
   &lt;li&gt;
      At this point we are listing on &lt;a href="http://localhost:8085/"&gt;http://localhost:8085/&lt;/a&gt;
   &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
   Additionally, I've snuck a new method in, ExtractResource(). This takes the name of
   an Embedded Resource (one that is INSIDE our test assembly) and puts it into a directory.
   In this case, I'm using the current AppDomain's directory, but you could certainly
   use Path.GetTempPath() if you like.
&lt;/p&gt;
&lt;div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 10pt; BACKGROUND: #ffffff; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: #000000; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Courier New"&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span style="COLOR: #0000ff"&gt;private&lt;/span&gt;&lt;span&gt; StringCollection extractedFilesToCleanup
      = &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;new&lt;/span&gt;&lt;span&gt; StringCollection();&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span style="COLOR: #0000ff"&gt;private&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt; string&lt;/span&gt;&lt;span&gt; ExtractResource(&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;string&lt;/span&gt;&lt;span&gt; filename, &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;string&lt;/span&gt;&lt;span&gt; directory)&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;{&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assembly a = Assembly.GetExecutingAssembly();&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;string&lt;/span&gt;&lt;span&gt; filePath
      = &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;string&lt;/span&gt;&lt;span&gt; path
      = &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;using&lt;/span&gt;&lt;span&gt;(Stream
      stream = a.GetManifestResourceStream("Corillian.Voyager.Web.Test." + filename))&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; filePath = Path.Combine(directory,filename);&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; path = filePath;&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;using&lt;/span&gt;&lt;span&gt;(StreamWriter
      outfile = File.CreateText(filePath))&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;using&lt;/span&gt;&lt;span&gt; (StreamReader
      infile = &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;new&lt;/span&gt;&lt;span&gt; StreamReader(stream))&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
      outfile.Write(infile.ReadToEnd());&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; extractedFilesToCleanup.Add(filePath);&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;return&lt;/span&gt;&lt;span&gt; filePath;&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;}&lt;/span&gt;
   &lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
   The ExtractResource method takes a filename and directory (and could, if you like,
   take a namespace, although I've hardcoded mine) and pulls a file as a Stream of bytes
   that was embedded as a resource in our Assembly and puts it into a directory. Hence
   the name, ExtractResource(). There is a StringCollection called extractedFilesToCleanup
   that keeps track of all the files we'll want to delete at the end of these tests,
   in [TestFixtureTearDown].
&lt;/p&gt;
&lt;p&gt;
   At this point, I've got a web.config (which was important to my tests, and will be
   looked at by Cassini/System.Web.Hosting) and a test1.aspx and test2.aspx in my current
   directory. The Cassini Web Server is started up and listing on port 8085 for HttpRequests.
   I also turned Page Tracing on in the web.config which will allow me to make certain
   Assertions about what kinds of code were called by the Page and helper classes within
   the Cassini ASP.NET context.
&lt;/p&gt;
&lt;p&gt;
   I'll add a helper method to create HttpRequests and return the response as a string:
&lt;/p&gt;
&lt;div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 10pt; BACKGROUND: #ffffff; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: #000000; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Courier New"&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span style="COLOR: #0000ff"&gt;private&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt; string&lt;/span&gt;&lt;span&gt; GetPage(&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;string&lt;/span&gt;&lt;span&gt; page)&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;{&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; WebClient client = &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;new&lt;/span&gt;&lt;span&gt; WebClient();&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;string&lt;/span&gt;&lt;span&gt; url
      = &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;new&lt;/span&gt;&lt;span&gt; Uri(&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;new&lt;/span&gt;&lt;span&gt; Uri(webServerUrl),page).ToString();&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;using&lt;/span&gt;&lt;span&gt; (StreamReader
      reader = &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;new&lt;/span&gt;&lt;span&gt; StreamReader(client.OpenRead(url)))&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;string&lt;/span&gt;&lt;span&gt; result
      = reader.ReadToEnd();&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;return&lt;/span&gt;&lt;span&gt; result;&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;}&lt;/span&gt;
   &lt;/p&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
   Now I can write some tests! My tests need to test things like the overridden behavior
   of custom BasePages (derived from System.Web.UI.Page) as well as some helper functions
   that require (to be TRULY tested) an HttpContext. However, I don't want the hassle
   of a CodeBehind or a lot of&amp;nbsp;other files, and certainly not the effort of a whole
   separate test project, so I'll make&amp;nbsp;my ASPX pages self contained using &amp;lt;%
   @Assembly %&amp;gt; directives. So, for example:&amp;nbsp;
&lt;/p&gt;
&lt;div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 10pt; BACKGROUND: #ffffff; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: #000000; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Courier New"&gt;&lt;span&gt;
   &lt;p&gt;
      &lt;font color="#ff0000"&gt;&lt;strong&gt;&amp;lt;%@ Assembly Name="Corillian.Voyager.Web.Common"
      %&amp;gt;&lt;/strong&gt;
      &lt;br /&gt;
      &lt;/font&gt;&amp;lt;%@ Page Language="C#" &lt;strong&gt;&lt;font color="#ff0000"&gt;Inherits="Corillian.Voyager.Web.Common.SharedBasePage" &lt;/font&gt;&lt;/strong&gt;%&amp;gt;&lt;br /&gt;
      &amp;lt;script runat="server"&amp;gt;&lt;br /&gt;
      &amp;nbsp;&amp;nbsp;&amp;nbsp; public void Page_Load(object sender, EventArgs e )&lt;br /&gt;
      &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;
      &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Label1.Text = "Hello";&lt;br /&gt;
      &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;
      &amp;lt;/script&amp;gt;&lt;br /&gt;
      &amp;lt;html&amp;gt;&lt;br /&gt;
      &amp;nbsp; &amp;lt;body&amp;gt;&lt;br /&gt;
      &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;form runat="server"&amp;gt;&lt;br /&gt;
      &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;p&amp;gt;&lt;br /&gt;
      &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;asp:Label id="Label1"
      runat="server"&amp;gt;Label&lt;br /&gt;
      &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/asp:Label&amp;gt;&lt;br /&gt;
      &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/p&amp;gt;&lt;br /&gt;
      &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/form&amp;gt;&lt;br /&gt;
      &amp;nbsp; &amp;lt;/body&amp;gt;&lt;br /&gt;
      &amp;lt;/html&amp;gt;&lt;br /&gt;
   &lt;/p&gt;
   &lt;/span&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
   A test to determine if this page&amp;nbsp;executed successfully&amp;nbsp;might look like:
&lt;/p&gt;
&lt;div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 10pt; BACKGROUND: #ffffff; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: #000000; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Courier New"&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;[Test]&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span style="COLOR: #0000ff"&gt;public&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt; void&lt;/span&gt;&lt;span&gt; BasicSmokeTestOfWebServer()&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;{&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;string&lt;/span&gt;&lt;span&gt; result
      = GetPage("test1.aspx");&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Assert.IsTrue(result.IndexOf("Hello") != -1,"Basic smoke
      test of test1.aspx didn't find 'Hello' in response!");&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;}&lt;/span&gt;
   &lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
   &lt;!--EndFragment--&gt;You could easily&amp;nbsp;expand your tests to include NUnitASP, or
   continue to use WebClient with specific HttpHeaders like accept-language or user-agent.
   One of our QA guys uses&amp;nbsp;NUnit&amp;nbsp;to automate the IE WebServer Control, the
   manipulates the DHTML DOM to make Assertions.
&lt;/p&gt;
&lt;p&gt;
   Finally, my cleanup code is simple, deleting all the files we extracted as well as
   toasting the /bin&amp;nbsp;folder.
&lt;/p&gt;
&lt;div style="BORDER-RIGHT: windowtext 1pt solid; PADDING-RIGHT: 0pt; BORDER-TOP: windowtext 1pt solid; PADDING-LEFT: 0pt; FONT-SIZE: 10pt; BACKGROUND: #ffffff; PADDING-BOTTOM: 0pt; BORDER-LEFT: windowtext 1pt solid; COLOR: #000000; PADDING-TOP: 0pt; BORDER-BOTTOM: windowtext 1pt solid; FONT-FAMILY: Courier New"&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;[TestFixtureTearDown]&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span style="COLOR: #0000ff"&gt;public&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt; void&lt;/span&gt;&lt;span&gt; TearDown()&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;{&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;try&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;if&lt;/span&gt;&lt;span&gt; (webServer
      != &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;null&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; webServer.Stop();&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; webServer = &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;null&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; CleanupResources();&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Directory.Delete(tempBinPath,&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;true&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;catch&lt;/span&gt;&lt;span&gt;{}&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;}&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &amp;nbsp;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span style="COLOR: #0000ff"&gt;private&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt; void&lt;/span&gt;&lt;span&gt; CleanupResources()&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;{&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;try&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;foreach&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;string&lt;/span&gt;&lt;span&gt; file &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;in&lt;/span&gt;&lt;span&gt; extractedFilesToCleanup)&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; File.Delete(file);&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="COLOR: #0000ff"&gt;catch&lt;/span&gt;&lt;span&gt; (Exception
      ex)&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Debug.WriteLine(ex.ToString());&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;
   &lt;/p&gt;
   &lt;p style="MARGIN: 0px"&gt;
      &lt;span&gt;}&lt;/span&gt;
   &lt;/p&gt;
&lt;/div&gt;
&lt;!--EndFragment--&gt;
&lt;p&gt;
   Now the WebServer, Test Cases and Test are nicely self-contained and can be moved
   to the CruiseControl.NET Continuous Integration Build Server.&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
   Enjoy. I did.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=944a5284-6b8d-4366-81e8-2e241401e1b3"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=944a5284-6b8d-4366-81e8-2e241401e1b3</comments>
      <category>ASP.NET</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=dfea663b-1764-4b4b-a06b-19105cb306ea</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=dfea663b-1764-4b4b-a06b-19105cb306ea</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=dfea663b-1764-4b4b-a06b-19105cb306ea</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=dfea663b-1764-4b4b-a06b-19105cb306ea</wfw:commentRss>
      <slash:comments>10</slash:comments>
      <title>Opportunity: Windows is completely missing the TextMode boat...</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=dfea663b-1764-4b4b-a06b-19105cb306ea</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=dfea663b-1764-4b4b-a06b-19105cb306ea</link>
      <pubDate>Wed, 01 Dec 2004 00:11:46 GMT</pubDate>
      <description>&lt;p&gt;
   With all this talk of shiny Avalon, I'm surprised that more people aren't mentioning
   "text-mode" applications.&amp;nbsp; I assume we all realize that there are literally millions
   of Windows machines from 95 to XP that exist only to allow more than one Telnet/ProcommPlus/Terminal
   window at a time, so end-users can interact with remote systems.
&lt;/p&gt;
&lt;p&gt;
   Point of Sale is a huge example:
&lt;/p&gt;
&lt;ul&gt;
   &lt;li&gt;
      Blockbuster Video &amp;ndash; I'd hate to have the video store guy have to reach for a
      mouse and click on a Gray Screen button OR a shiny Avalon Form.&lt;/li&gt;
   &lt;li&gt;
      Toyota Service &amp;ndash; Searching for Parts, making service appoinments, it's considerably
      faster in text mode than any *.*Forms technology, and I've seen them open as many
      as 8 windows at a time.&lt;/li&gt;
   &lt;li&gt;
      Teller Banking Systems &amp;ndash; Many banks are changing their TextMode systems over
      to intranets, and I personally waited 90 mins at a large bank last week to open a
      checking account, while I watch the teller move between three intranet ASP applications
      and two Word Macros, then attaching the Word files to an Outlook Email.&amp;nbsp; This
      same process, in text mode, at First Technology Credit Union took 10 mins.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
   I'd like to see how far someone could take the new Colored Console support in Whidbey
   and make me a forms renderer.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
   I&amp;rsquo;m just saying that my Tab,Tab,Tab,Enter will beat your Click,Tab,Alt-F,O,Click,Double-Click,
   more often than not and I will take the Pepsi Challenge otherwise. :)&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
   Am I nuts to think that Windows is missing the text-mode boat?
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=dfea663b-1764-4b4b-a06b-19105cb306ea"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=dfea663b-1764-4b4b-a06b-19105cb306ea</comments>
      <category>Musings</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=8d70a8f7-bd1c-45a4-9d64-0078e4e4ceb4</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=8d70a8f7-bd1c-45a4-9d64-0078e4e4ceb4</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=8d70a8f7-bd1c-45a4-9d64-0078e4e4ceb4</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=8d70a8f7-bd1c-45a4-9d64-0078e4e4ceb4</wfw:commentRss>
      <slash:comments>0</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
      Here's a darned useful thing, the equivalent of a KB Serach for CSS and JavaScript
      bugs.
   </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <!--StartFragment -->
            <em>This is very useful: </em>
            <a href="http://www.quirksmode.org/bugreports/">
              <em>QuirksMode
      Bug Reports</em>
            </a>
            <em>, "entirely dedicated to finding, mending, and publishing
      CSS and JavaScript browser bugs." You can search by browser or by keyword, or just
      go to that page to see the last seven reported bugs. </em>[<a href="http://www.webstandards.org/buzz/archive/2004_11.html#a000469">WebStandards</a>]
   </p>
        </blockquote>
        <p>
       
   </p>
        <img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=8d70a8f7-bd1c-45a4-9d64-0078e4e4ceb4" />
      </body>
      <title>QuirksMode Bug Reports - CSS and JavaScript Weirdness Search Engine</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=8d70a8f7-bd1c-45a4-9d64-0078e4e4ceb4</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=8d70a8f7-bd1c-45a4-9d64-0078e4e4ceb4</link>
      <pubDate>Tue, 30 Nov 2004 19:28:26 GMT</pubDate>
      <description>&lt;p&gt;
   Here's a darned useful thing, the equivalent of a KB Serach for CSS and JavaScript
   bugs.
&lt;/p&gt;
&lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt;
&lt;p&gt;
   &lt;!--StartFragment --&gt;&lt;em&gt;This is very useful: &lt;/em&gt;&lt;a href="http://www.quirksmode.org/bugreports/"&gt;&lt;em&gt;QuirksMode
   Bug Reports&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, "entirely dedicated to finding, mending, and publishing
   CSS and JavaScript browser bugs." You can search by browser or by keyword, or just
   go to that page to see the last seven reported bugs. &lt;/em&gt;[&lt;a href="http://www.webstandards.org/buzz/archive/2004_11.html#a000469"&gt;WebStandards&lt;/a&gt;]
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;
   &amp;nbsp;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=8d70a8f7-bd1c-45a4-9d64-0078e4e4ceb4"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=8d70a8f7-bd1c-45a4-9d64-0078e4e4ceb4</comments>
      <category>Musings</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=5454b87f-b15f-4f22-920c-b530f8cdb2cc</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=5454b87f-b15f-4f22-920c-b530f8cdb2cc</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=5454b87f-b15f-4f22-920c-b530f8cdb2cc</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=5454b87f-b15f-4f22-920c-b530f8cdb2cc</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <a href="http://www.testdriven.net/Portals/0/content_vs1.png">
            <img alt="" hspace="0" src="http://www.testdriven.net/Portals/0/content_vs1-small.png" align="right" border="0" />
          </a>It
      just kills me - literally tears me up inside - to watch people with both NUnitGui
      and Visual Studio.NET open who painfully switch back and forth, opening DLLs, attaching
      to processes, and generally cobbling together a sense of TDD.
   </p>
        <p>
      Tell me you wouldn't rather right-click and say "Run Test" or "Test With...Debugger."
   </p>
        <p>
      You may have used NUnitAddIn, which was a godsend. Today, Jamie and team launched <a href="http://www.testdriven.net/Default.aspx?ReferrerId=62">T</a><a href="http://www.testdriven.net/Default.aspx?ReferrerId=62">estDriven.NET
      1.0</a> with full support for NUnit, csUnit, MbUnit AND Visual Studio Team System.
   </p>
        <p>
      Naysayers may dismiss <a href="http://www.testdriven.net/Default.aspx?ReferrerId=62">TestDriven.NET</a> as
      a simple Add-In with modified right-click context menu, but there's much more than
      that. You run your tests in their own runner process, which gives you side-effect
      free testing. If you have different projects using different testing frameworks, their
      tests are all runnable with the same right-click/"Run Test" experience.  You
      can right-click on a single method and debug it. I love it.
   </p>
        <p>
      You can run tests with NUnitGui, sure, but the Visual Studio integration goes very
      deep. I even show this integration in sales meetings. When you hit Build, the output
      window's combobox says "Build", of course. When you "Run Test" you'll see "Build"
      then "Test" immediately. This is what folks were aiming for when continuous integration
      and TDD.
   </p>
        <p>
      I literally don't know how I managed before TDD, and you'll have to pry this <strong><a href="http://www.testdriven.net/Default.aspx?ReferrerId=62">free
      tool</a></strong>from my cold, dead hands.
   </p>
        <p>
      Thanks Jamie and Team, this is great stuff.
   </p>
        <p>
      I particularly like the last question in the short registration/survey, and I wish
      more people would ask it!
   </p>
        <ul>
          <li>
            <em>How did you answer these questions? (it will *not* be held against you!)</em>
          </li>
          <ul>
            <li>
              <em>I answered them honestly</em>
            </li>
            <li>
              <em>Randomly to get to the download</em>
            </li>
          </ul>
        </ul>
        <img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=5454b87f-b15f-4f22-920c-b530f8cdb2cc" />
      </body>
      <title>TestDriven.NET 1.0 Launch - What are you waiting for?</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=5454b87f-b15f-4f22-920c-b530f8cdb2cc</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=5454b87f-b15f-4f22-920c-b530f8cdb2cc</link>
      <pubDate>Mon, 29 Nov 2004 20:34:51 GMT</pubDate>
      <description>&lt;p&gt;
   &lt;a href="http://www.testdriven.net/Portals/0/content_vs1.png"&gt;&lt;img alt="" hspace="0" src="http://www.testdriven.net/Portals/0/content_vs1-small.png" align="right" border="0"&gt;&lt;/a&gt;It
   just kills me - literally tears me up inside - to watch people with both NUnitGui
   and Visual Studio.NET open who painfully switch back and forth, opening DLLs, attaching
   to processes, and generally cobbling together a sense of TDD.
&lt;/p&gt;
&lt;p&gt;
   Tell me you wouldn't rather right-click and say "Run Test" or "Test With...Debugger."
&lt;/p&gt;
&lt;p&gt;
   You may have used NUnitAddIn, which was a godsend.&amp;nbsp;Today, Jamie and team launched &lt;a href="http://www.testdriven.net/Default.aspx?ReferrerId=62"&gt;T&lt;/a&gt;&lt;a href="http://www.testdriven.net/Default.aspx?ReferrerId=62"&gt;estDriven.NET
   1.0&lt;/a&gt; with full support for NUnit, csUnit, MbUnit AND Visual Studio Team System.
&lt;/p&gt;
&lt;p&gt;
   Naysayers may dismiss &lt;a href="http://www.testdriven.net/Default.aspx?ReferrerId=62"&gt;TestDriven.NET&lt;/a&gt; as
   a simple Add-In with modified right-click context menu, but there's much more than
   that. You run your tests in their own runner process, which gives you side-effect
   free testing. If you have different projects using different testing frameworks, their
   tests are all runnable with the same right-click/"Run Test" experience.&amp;nbsp; You
   can right-click on a single method and debug it.&amp;nbsp;I love it.
&lt;/p&gt;
&lt;p&gt;
   You can run tests with NUnitGui, sure, but the Visual Studio integration goes very
   deep. I even show this integration in sales meetings. When you hit Build, the output
   window's combobox says "Build", of course. When you "Run Test" you'll see "Build"
   then "Test" immediately. This is what folks were aiming for when continuous integration
   and TDD.
&lt;/p&gt;
&lt;p&gt;
   I literally don't know how I managed before TDD, and you'll have to pry this &lt;strong&gt;&lt;a href="http://www.testdriven.net/Default.aspx?ReferrerId=62"&gt;free
   tool&lt;/a&gt; &lt;/strong&gt;from my cold, dead hands.
&lt;/p&gt;
&lt;p&gt;
   Thanks Jamie and Team, this is great stuff.
&lt;/p&gt;
&lt;p&gt;
   I particularly like the last question in the short registration/survey, and I wish
   more people would ask it!
&lt;/p&gt;
&lt;ul&gt;
   &lt;li&gt;
      &lt;em&gt;How did you answer these questions? (it will *not* be held against you!)&lt;/em&gt;
   &lt;/li&gt;
   &lt;ul&gt;
      &lt;li&gt;
         &lt;em&gt;I answered them honestly&lt;/em&gt;
      &lt;/li&gt;
      &lt;li&gt;
         &lt;em&gt;Randomly to get to the download&lt;/em&gt;
      &lt;/li&gt;
   &lt;/ul&gt;
&lt;/ul&gt;
&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=5454b87f-b15f-4f22-920c-b530f8cdb2cc"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=5454b87f-b15f-4f22-920c-b530f8cdb2cc</comments>
      <category>Musings</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=03a69bf8-b19f-4779-a037-43ee26057951</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=03a69bf8-b19f-4779-a037-43ee26057951</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=03a69bf8-b19f-4779-a037-43ee26057951</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=03a69bf8-b19f-4779-a037-43ee26057951</wfw:commentRss>
      <slash:comments>3</slash:comments>
      <title>Scott Hanselman's Holiday List</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=03a69bf8-b19f-4779-a037-43ee26057951</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=03a69bf8-b19f-4779-a037-43ee26057951</link>
      <pubDate>Mon, 29 Nov 2004 06:42:41 GMT</pubDate>
      <description>&lt;p&gt;
   I'm beating the Christmas/Chanukah/Kwanzaa/Festivus rush, and &lt;a href="http://amazon.com/gp/registry/1FLR2FIFT375B/diabeticbooks"&gt;posting
   my wants-list now&lt;/a&gt;. :) This is also known as my &lt;a href="http://amazon.com/gp/registry/1FLR2FIFT375B/diabeticbooks"&gt;stuff-I-may-buy-if-you-don't-give-it-to-me
   list&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
   Enjoy. In no particular order.
&lt;/p&gt;
&lt;p&gt;
   &lt;strong&gt;Games&lt;/strong&gt;
&lt;/p&gt;
&lt;ul&gt;
   &lt;li&gt;
      &lt;a href="http://www.amazon.com/o/ASIN/B0002CHJA0/diabeticbooks"&gt;Tom Clancy's Ghost
      Recon 2&lt;/a&gt;&amp;nbsp;- I'm loving the squad-based shooters&lt;/li&gt;
   &lt;li&gt;
      &lt;a href="http://www.amazon.com/o/ASIN/B0002CHJ3W/diabeticbooks"&gt;Prince of Persia 2&lt;/a&gt;&amp;nbsp;-
      I'm about 85% through the first one, and it's the best 3D platformer ever&lt;/li&gt;
   &lt;li&gt;
      &lt;a href="http://www.amazon.com/o/ASIN/B0002IQC8Y"&gt;Burnout 3&lt;/a&gt;&amp;nbsp;- Never heard
      of it, but the folks who play it won't shut up about it and it would be one more game
      to use my &lt;a href="http://www.amazon.com/o/ASIN/B00005QEZ8/diabeticbooks"&gt;Xbox Wheel
      Controller&lt;/a&gt;
   &lt;/li&gt;
   &lt;li&gt;
      &lt;a href="http://www.amazon.com/o/ASIN/B00064MUIA/diabeticbooks"&gt;Nintendo DS&lt;/a&gt; -
      I think I'll wait until the frenzy dies down, but this seems too cool not to have.
      I'd probably get &lt;a href="http://www.amazon.com/o/ASIN/B0006B0O9U/diabeticbooks"&gt;Mario&lt;/a&gt;,
      and &lt;a href="http://www.amazon.com/o/ASIN/B00069ZIO8/diabeticbooks"&gt;Rayman&lt;/a&gt;. Might
      be time to start taking the bus to work...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
   &lt;strong&gt;Music and Books&lt;/strong&gt;
&lt;/p&gt;
&lt;ul&gt;
   &lt;li&gt;
      &lt;a href="http://www.amazon.com/o/ASIN/B00000K3HT/diabeticbooks"&gt;Adrianna Evans&lt;/a&gt;&amp;nbsp;-
      I dig the neo-soul&lt;/li&gt;
   &lt;li&gt;
      &lt;div align="left"&gt;&lt;a href="http://www.amazon.com/o/ASIN/B000002N2B/diabeticbooks"&gt;Meshell
         Ndegeocello&lt;/a&gt; - Smooth sounds
      &lt;/div&gt;
   &lt;/li&gt;
   &lt;li&gt;
      &lt;div align="left"&gt;&lt;a href="http://www.amazon.com/o/ASIN/B00000K3HO/diabeticbooks"&gt;Davina&lt;/a&gt; -
         More music that somehow never hits the radio
      &lt;/div&gt;
   &lt;/li&gt;
   &lt;li&gt;
      &lt;div align="left"&gt;&lt;a href="http://www.amazon.com/o/ASIN/B00015YW8U/diabeticbooks"&gt;Amel
         Larrieux&lt;/a&gt; - Come on, people, you at least remember Groove Theory?
      &lt;/div&gt;
   &lt;/li&gt;
   &lt;li&gt;
      &lt;div align="left"&gt;&lt;a href="http://www.amazon.com/o/ASIN/B0001BKAGM/diabeticbooks"&gt;Van
         Hunt&lt;/a&gt; - Heir to Marvin's throne...
      &lt;/div&gt;
   &lt;/li&gt;
   &lt;li&gt;
      &lt;div align="left"&gt;Anything from &lt;a href="http://www.amazon.com/exec/obidos/tg/guides/guide-display/-/2IXCJIREYUIIH/ref=cm_bg_guides/002-3972324-0322457"&gt;this
         neo-soul list&lt;/a&gt;...although I have most of these...
      &lt;/div&gt;
   &lt;/li&gt;
   &lt;li&gt;
      &lt;div align="left"&gt;&lt;a href="http://www.amazon.com/o/ASIN/0380977761/diabeticbooks"&gt;Abraham
         : A Journey to the Heart of Three Faiths&lt;/a&gt; - So I can give my borrowed copy back
   &lt;/li&gt;&gt;
&lt;/ul&gt;
&lt;p align="left"&gt;
   &lt;strong&gt;Electronics&lt;/strong&gt;
&lt;/p&gt;
&lt;ul&gt;
   &lt;li&gt;
      &lt;div align="left"&gt;&lt;a href="http://www.amazon.com/o/ASIN/B0002ZAEY0/diabeticbooks"&gt;iPod
         60gig Photo&lt;/a&gt; - My 15gig is totally full, and I'd love to move photos from my camera
         when on long trips. I hate thinking about storage
      &lt;/div&gt;
   &lt;/li&gt;
   &lt;li&gt;
      &lt;div align="left"&gt;&lt;a href="http://www.amazon.com/o/ASIN/B0002GDIII/diabeticbooks"&gt;Airport
         Express&lt;/a&gt; - I wouldn't mind streaming some music to the downstairs stereo either
      &lt;/div&gt;
   &lt;/li&gt;
   &lt;li&gt;
      &lt;div align="left"&gt;&lt;a href="http://www.amazon.com/o/ASIN/B00017IX10/diabeticbooks"&gt;Altec-Lansing
         iPod Portable Speakers&lt;/a&gt;&amp;nbsp;- My speakers at work are crap...
      &lt;/div&gt;
   &lt;/li&gt;
   &lt;li&gt;
      &lt;div align="left"&gt;Actually, scratch that last one, I'd rather have a &lt;a href="http://www.amazon.com/o/ASIN/B0002HA7OK/diabeticbooks"&gt;Tivoli
         iPal&lt;/a&gt;
      &lt;/div&gt;
   &lt;/li&gt;
   &lt;li&gt;
      &lt;div align="left"&gt;&lt;a href="http://www.amazon.com/o/ASIN/B0002Y6DGO/diabeticbooks"&gt;Casio
         Exilim EXZ55&lt;/a&gt; - Can't say enough nice things about the Exilim series
      &lt;/div&gt;
   &lt;/li&gt;
   &lt;li&gt;
      &lt;div align="left"&gt;&lt;a href="http://www.amazon.com/o/ASIN/B0001IXUF8/diabeticbooks"&gt;Panasonic
         SA-XR50&lt;/a&gt; - One of the first truly digital receivers. There's no DAC!
      &lt;/div&gt;
   &lt;/li&gt;
   &lt;li&gt;
      &lt;div align="left"&gt;The wife will never let me get this &lt;a href="http://www.amazon.com/o/ASIN/B00009MDBY/diabeticbooks"&gt;37"
         LCD HD TV&lt;/a&gt;
      &lt;/div&gt;
   &lt;/li&gt;
&lt;/ul&gt;
&lt;p align=left&gt;
   &lt;strong&gt;Gadgets and Misc&lt;/strong&gt;
&lt;/p&gt;
&lt;ul&gt;
   &lt;li&gt;
      Anything from &lt;a href="http://www.despair.com/"&gt;http://www.despair.com/&lt;/a&gt;
   &lt;/li&gt;
   &lt;li&gt;
      Any &lt;a href="http://www.phidgetsusa.com/index.asp"&gt;Phidgets&lt;/a&gt;, but especially the &lt;a href="http://www.phidgetsusa.com/viewproduct.asp?sku="1111""&gt;Motion
      Sensor&lt;/a&gt;&amp;nbsp;and &lt;a href="http://www.phidgetsusa.com/viewproduct.asp?SKU=1013"&gt;Interface
      Kit 8/8/8&lt;/a&gt;&amp;nbsp;with &lt;a href="http://www.phidgetsusa.com/viewproduct.asp?SKU=3005"&gt;Power
      Supply&lt;/a&gt;
   &lt;/li&gt;
   &lt;li&gt;
      A &lt;a href="http://www.crystalfontz.com/products/634usb/index.html"&gt;CFA634-TMC-KU&lt;/a&gt;&amp;nbsp;so
      I can hook it up to iTunes&lt;/li&gt;
&lt;/ul&gt;
&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=03a69bf8-b19f-4779-a037-43ee26057951"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=03a69bf8-b19f-4779-a037-43ee26057951</comments>
      <category>Musings</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=eee6c8d2-0e8b-4356-b602-853f909f3d6d</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=eee6c8d2-0e8b-4356-b602-853f909f3d6d</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=eee6c8d2-0e8b-4356-b602-853f909f3d6d</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=eee6c8d2-0e8b-4356-b602-853f909f3d6d</wfw:commentRss>
      <slash:comments>0</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <em>"The Internet combines the excitement of typing with the reliability of anonymous
      hearsay."<br />
          -</em>
            <a href="http://www.amazon.com/o/ASIN/0446532681/diabeticbooks">
              <em>America
      (The Book): A Citizen's Guide to Democracy Inaction</em>
            </a>
          </p>
        </blockquote>
        <img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=eee6c8d2-0e8b-4356-b602-853f909f3d6d" />
      </body>
      <title>Today's Quote - "The Internet combines the excitement of typing with the reliability of anonymous hearsay."</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=eee6c8d2-0e8b-4356-b602-853f909f3d6d</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=eee6c8d2-0e8b-4356-b602-853f909f3d6d</link>
      <pubDate>Fri, 26 Nov 2004 01:31:39 GMT</pubDate>
      <description>&lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt;
&lt;p&gt;
   &lt;em&gt;"The Internet combines the excitement of typing with the reliability of anonymous
   hearsay."&lt;br /&gt;
   &amp;nbsp;&amp;nbsp;&amp;nbsp; -&lt;/em&gt;&lt;a href="http://www.amazon.com/o/ASIN/0446532681/diabeticbooks"&gt;&lt;em&gt;America
   (The Book): A Citizen's Guide to Democracy Inaction&lt;/em&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/blockquote&gt;&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=eee6c8d2-0e8b-4356-b602-853f909f3d6d"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=eee6c8d2-0e8b-4356-b602-853f909f3d6d</comments>
      <category>Musings</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=403babde-37bb-4562-9058-ade8eff87ec7</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=403babde-37bb-4562-9058-ade8eff87ec7</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=403babde-37bb-4562-9058-ade8eff87ec7</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=403babde-37bb-4562-9058-ade8eff87ec7</wfw:commentRss>
      <slash:comments>4</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
      I am subscribed to 168 RSS feeds.  I'm obviously creating work for myself, which
      may not be a good idea. Having only a 4k stack myself, I can't hold a lot of
      URLs in my head. Additionally, sometimes I just want to visit a website myself. 
   </p>
        <p>
      Here's the websites that I actually launch a browser for every morning (I have a macro
      in <a href="http://www.bayden.com/SlickRun/">Slickrun</a> called "morning" that does
      this):
   </p>
        <ul>
          <li>
            <a href="http://www.cnn.com">http://www.cnn.com</a> - World News</li>
          <li>
            <a href="http://www.news.com">http://www.news.com</a> - Tech News</li>
          <li>
            <a href="http://www.theonion.com">http://www.theonion.com</a> - Fake News</li>
          <li>
            <a href="http://news.google.com">http://news.google.com</a> - Aggregation of News</li>
          <li>
            <a href="http://www.larkware.com">http://www.larkware.com</a> - Programming Stuff
         and Useful Information that I should have found myself if I was paying attention,
         but I wasn't</li>
        </ul>
        <p>
      You have to give props to MikeG for (at the time of this blogging) 507 Daily Grinds. 
      I always find something interesting and useful in his daily rant. If you're a reader
      of mine, you should be a reader of Mike's as well. Here is the <em>Daily Grind RSS
      Feed</em> for your convenience: <a href="http://www.larkware.com/larkware2.xml"><img alt="" hspace="0" src="http://www.larkware.com/xml.gif" align="baseline" border="0" /></a></p>
        <img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=403babde-37bb-4562-9058-ade8eff87ec7" />
      </body>
      <title>Attention Bloggers: If you're not reading the Daily Grind, why not?</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=403babde-37bb-4562-9058-ade8eff87ec7</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=403babde-37bb-4562-9058-ade8eff87ec7</link>
      <pubDate>Wed, 24 Nov 2004 18:24:29 GMT</pubDate>
      <description>&lt;p&gt;
   I am subscribed to 168 RSS feeds.&amp;nbsp; I'm obviously creating work for myself, which
   may not be a good idea.&amp;nbsp;Having only a 4k stack myself, I can't hold a lot of
   URLs in my head. Additionally, sometimes I just want to visit a website myself. 
&lt;/p&gt;
&lt;p&gt;
   Here's the websites that I actually launch a browser for every morning (I have a macro
   in &lt;a href="http://www.bayden.com/SlickRun/"&gt;Slickrun&lt;/a&gt; called "morning" that does
   this):
&lt;/p&gt;
&lt;ul&gt;
   &lt;li&gt;
      &lt;a href="http://www.cnn.com"&gt;http://www.cnn.com&lt;/a&gt;&amp;nbsp;- World News&lt;/li&gt;
   &lt;li&gt;
      &lt;a href="http://www.news.com"&gt;http://www.news.com&lt;/a&gt;&amp;nbsp;- Tech News&lt;/li&gt;
   &lt;li&gt;
      &lt;a href="http://www.theonion.com"&gt;http://www.theonion.com&lt;/a&gt;&amp;nbsp;- Fake News&lt;/li&gt;
   &lt;li&gt;
      &lt;a href="http://news.google.com"&gt;http://news.google.com&lt;/a&gt; - Aggregation of News&lt;/li&gt;
   &lt;li&gt;
      &lt;a href="http://www.larkware.com"&gt;http://www.larkware.com&lt;/a&gt; - Programming Stuff
      and Useful Information that I should have found myself if I was paying attention,
      but I wasn't&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
   You have to give props to MikeG for (at the time of this blogging) 507 Daily Grinds.&amp;nbsp;
   I always find something interesting and useful in his daily rant. If you're a reader
   of mine, you should be a reader of Mike's as well. Here is the &lt;em&gt;Daily Grind RSS
   Feed&lt;/em&gt; for your convenience: &lt;a href="http://www.larkware.com/larkware2.xml"&gt;&lt;img alt="" hspace="0" src="http://www.larkware.com/xml.gif" align="baseline" border="0"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=403babde-37bb-4562-9058-ade8eff87ec7"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=403babde-37bb-4562-9058-ade8eff87ec7</comments>
      <category>Musings</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=c0d653a5-dbbe-4f4d-acd2-b5fd1852e0ea</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=c0d653a5-dbbe-4f4d-acd2-b5fd1852e0ea</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=c0d653a5-dbbe-4f4d-acd2-b5fd1852e0ea</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=c0d653a5-dbbe-4f4d-acd2-b5fd1852e0ea</wfw:commentRss>
      <slash:comments>4</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
      Just a small reminder for myself and others that you can set the title of the Command
      Prompt Window with the "<strong>TITLE</strong>" Batch Command.
   </p>
        <p>
      Since I'm building three different branches of our SDK during dev, it's nice to differentiate
      all these windows on all these monitors.
   </p>
        <p>
      For example here's "mybuild.bat"
   </p>
        <blockquote dir="ltr" style="MARGIN-RIGHT: 0px">
          <p>
            <font face="Courier New">
              <strong>
                <em>
                  <font color="#ff0000">TITLE Building VoyagerFramework
      2.0<br /></font>
                </em>
              </strong>set BUILDDIR=C:\dev\VoyagerFramework\build<br />
      call BUILD.BAT %1 %2 %3 %4 %5<br /></font>
          </p>
        </blockquote>
        <img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=c0d653a5-dbbe-4f4d-acd2-b5fd1852e0ea" />
      </body>
      <title>Setting the Title of the "DOS" Command Prompt from a Batch File</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=c0d653a5-dbbe-4f4d-acd2-b5fd1852e0ea</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=c0d653a5-dbbe-4f4d-acd2-b5fd1852e0ea</link>
      <pubDate>Mon, 22 Nov 2004 19:08:28 GMT</pubDate>
      <description>&lt;p&gt;
   Just a small reminder for myself and others that you can set the title of the Command
   Prompt Window with the "&lt;strong&gt;TITLE&lt;/strong&gt;" Batch Command.
&lt;/p&gt;
&lt;p&gt;
   Since I'm building three different branches of our SDK during dev, it's nice to differentiate
   all these windows on all these monitors.
&lt;/p&gt;
&lt;p&gt;
   For example here's "mybuild.bat"
&lt;/p&gt;
&lt;blockquote dir="ltr" style="MARGIN-RIGHT: 0px"&gt;
&lt;p&gt;
   &lt;font face="Courier New"&gt;&lt;strong&gt;&lt;em&gt;&lt;font color="#ff0000"&gt;TITLE Building VoyagerFramework
   2.0&lt;br /&gt;
   &lt;/font&gt;&lt;/em&gt;&lt;/strong&gt;set BUILDDIR=C:\dev\VoyagerFramework\build&lt;br /&gt;
   call BUILD.BAT %1 %2 %3 %4 %5&lt;br /&gt;
   &lt;/font&gt;
&lt;/p&gt;
&lt;/blockquote&gt;&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=c0d653a5-dbbe-4f4d-acd2-b5fd1852e0ea"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=c0d653a5-dbbe-4f4d-acd2-b5fd1852e0ea</comments>
      <category>Musings</category>
    </item>
    <item>
      <trackback:ping>http://www.hanselman.com/blog/Trackback.aspx?guid=98bd0e23-a0de-476d-a62a-ea2a614045b3</trackback:ping>
      <pingback:server>http://www.hanselman.com/blog/pingback.aspx</pingback:server>
      <pingback:target>http://www.hanselman.com/blog/PermaLink.aspx?guid=98bd0e23-a0de-476d-a62a-ea2a614045b3</pingback:target>
      <wfw:comment>http://www.hanselman.com/blog/CommentView.aspx?guid=98bd0e23-a0de-476d-a62a-ea2a614045b3</wfw:comment>
      <wfw:commentRss>http://www.hanselman.com/blog/SyndicationService.asmx/GetEntryCommentsRss?guid=98bd0e23-a0de-476d-a62a-ea2a614045b3</wfw:commentRss>
      <slash:comments>10</slash:comments>
      <title>A Hanselman Review: Doom 3 vs. FarCry vs. Half-Life 2 vs. Halo 2</title>
      <guid>http://www.hanselman.com/blog/PermaLink.aspx?guid=98bd0e23-a0de-476d-a62a-ea2a614045b3</guid>
      <link>http://www.hanselman.com/blog/PermaLink.aspx?guid=98bd0e23-a0de-476d-a62a-ea2a614045b3</link>
      <pubDate>Mon, 22 Nov 2004 02:36:19 GMT</pubDate>
      <description>&lt;p&gt;
   Believe it or not, I'm not a big gamer.&amp;nbsp; By 'not a big gamer' I mean, I didn't
   take a week off work to play &lt;a href="http://www.amazon.com/o/ASIN/B0001VGFK2/diabeticbooks"&gt;GTA:
   San Andreas&lt;/a&gt; as a co-worker did.&amp;nbsp; By 'not a big gamer' I mean, I lost interest
   with &lt;a href="http://www.amazon.com/o/ASIN/B00008KTNW/diabeticbooks"&gt;Ninja Gaiden&lt;/a&gt; because
   it was too freaking hard. I've got about 2 hours patience with a game, but I stop
   when I start to hurt, be it hands, back or head.
&lt;/p&gt;
&lt;p align=left&gt;
   That said, you'd think I &lt;em&gt;was&lt;/em&gt;&amp;nbsp;a gamer as in the last two months I've
   picked up &lt;a href="http://www.amazon.com/o/ASIN/B00006C2HA/diabeticbooks"&gt;Doom 3&lt;/a&gt;, &lt;a href="http://www.amazon.com/o/ASIN/B0000A1VER/diabeticbooks"&gt;FarCry&lt;/a&gt;, &lt;a href="http://www.amazon.com/o/ASIN/B00006I02Z/diabeticbooks"&gt;Half-Life
   2&lt;/a&gt;, and &lt;a href="http://www.amazon.com/o/ASIN/B00008J7NZ/diabeticbooks"&gt;Halo 2&lt;/a&gt;.
   These games, unquestionably, represent the pinnacle - thus far - of &lt;a href="http://internetgames.about.com/library/glossary/bldef-fps.htm"&gt;FPS&lt;/a&gt;-style
   gaming. The first three are PC while Halo 2 is on XBox. I'm playing the PC games on
   a P4-4Ghz with a gig of Ram and an ATI&amp;nbsp;Radeon 9600 Pro.
&lt;/p&gt;
&lt;p align=left&gt;
   There's been a million reviews of all these games from &lt;a href="http://www.anandtech.com/"&gt;AnandTech&lt;/a&gt;-type
   reviews that tell you how much internal processor cache you &lt;em&gt;must have &lt;/em&gt;to
   enjoy these games, to &lt;a href="http://www.tomshardware.com/"&gt;TomsHardware&lt;/a&gt;-type&amp;nbsp;reviews
   that are meant to sell $500 video cards with heat sinks and fans of their own, to
   12-year old blogger/reviewers who let you know about the latest mods and cheats so
   they can embarrass my 30-year old ass on multi-player maps. (You'll be happy to hear
   that I (and my ego) &lt;em&gt;no longer&lt;/em&gt;&amp;nbsp;need to defeat these infidels to feel
   secure. I just cry tiny tears and leave it at that.)
&lt;/p&gt;
&lt;p align=left&gt;
   That said, I wanted to write up what &lt;strong&gt;&lt;em&gt;I&lt;/em&gt;&lt;/strong&gt; thought was important
   about these games, and what drives my opinion and buying decisions around gaming.
   These categories may be slightly different than the typical review. Or not.
&lt;/p&gt;
&lt;p align=left&gt;
   &lt;strong&gt;Story&lt;/strong&gt;
&lt;/p&gt;
&lt;p align=left&gt;
   &lt;table border=1&gt;
      &lt;tbody&gt;
         &lt;tr&gt;
            &lt;th&gt;
               Game&lt;/th&gt;
            &lt;th&gt;
               My Thoughts&lt;/th&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006C2HA/diabeticbooks"&gt;Doom 3&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               While Doom 3 tries harder than it's predecessors, there's little story to speak of.
               Some crazy stuff happens on Mars and you're a Mars Marine who has to single-handedly
               kill everyone. There are some interactions with other characters but it's largely
               as you stumble upon them doing something else, and you can't assist them. They are
               usually killed as you walk away. The "scripting" feels a little stilted to me. There
               are a few clever places where the camera backs out of your first-person view into
               a third person view when you "trigger" an event. Perhaps a monster is making in entrance.
               Then the camera pushes in to the back of your head and control returns to you to take
               care of business. It's fairly predictable as you can "feel" when it should happen.&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B0000A1VER/diabeticbooks"&gt;FarCry&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               You'll notice a pattern here as "single-handedly" is pretty common in the FPS space.
               In FarCry, you're on vacation when your wife is kidnapped and you are unwittingly
               and unwillingly pulled into a terrorist plot to do some crazy stuff. You have to single-handedly
               kill everyone.&amp;nbsp; Every once in a while, a benefactor in the form of a scientist
               on the project meets up with you to help out.&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006I02Z/diabeticbooks"&gt;Half-Life 2&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               The original Half-Life set a whole new level for story quality and I believe Half-Life&amp;nbsp;2
               is even more extraordinary. There is constant interaction with the NPCs and a real
               sense of total immersion that I honestly haven't felt since "Bard's Tale." There's
               many places where you find your self asking "what's the story here? There's something
               I'm not seeing or being told." That sense of curiosity continues to push you forward
               through the narrative. It's also worth noting that the realism in the faces and expressions
               of the characters is truly amazing and really underscores the uniqueness of people.
               Rather than dozens of carbon copy NPCs, each character is totally unique and could
               be recognized in a crowd later. "Oh! It's this guy again" happens a lot. Additionally
               since the "action button" doubles as the pick-stuff-up-and-optionally-throw-it button,
               there are a number of things you can do to interact with the environment.&amp;nbsp;I'd
               say that Half-Life 2 has the most interactive world of any game I've played. You can
               blow up anything, stack objects, throw objects, flip over tables and hide behind them,
               toss TVs out windows, and break things with your crowbar.&amp;nbsp; I was impressed with
               the attention to detail yesterday when I broke a window with the crowbar, expecting
               the whole window to break out, and instead, as it was safety glass, the window shatter,
               but stayed together, and I had to clear it out with additionally specifically-placed
               blows. This level of detail means that things in Half-Life 2 work as they should (as
               they do in the real world) so rather than learning the physics of the Half-Life world,
               you can use your knowledge of the real world in this artificial one. This increases
               the overall enjoyment of the game greatly.&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00008J7NZ/diabeticbooks"&gt;Halo 2&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               Halo 2's single player story is even more compelling than the others as there are
               extensive movie-like cut scenes of some length that explain the context of the larger
               story.&amp;nbsp; Additionally you will end up playing as &lt;em&gt;more than one character &lt;/em&gt;later
               in the game which deepens your involvement and causes you to wonder who are&amp;nbsp;the
               good guys and who are the bad guys, and gives the game less of an "us vs. them" narrative
               and more of a "us vs. them and them vs. three or four other folks."&lt;/td&gt;
         &lt;/tr&gt;
      &lt;/tbody&gt;
   &lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;
   &lt;strong&gt;Puzzles&lt;/strong&gt;
&lt;/p&gt;
&lt;p align=left&gt;
   &lt;table border=1&gt;
      &lt;tbody&gt;
         &lt;tr&gt;
            &lt;th&gt;
               Game&lt;/th&gt;
            &lt;th&gt;
               My Thoughts&lt;/th&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006C2HA/diabeticbooks"&gt;Doom 3&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               Most of the puzzles in Doom 3 are pretty stock and fairly lame. Find this key from
               that guy's body. Open that door. Find this code from this guys personal log. Open
               that door. Only once (so far) is there a "move this barrel" puzzle and then it's just
               to throw them in the trash. Mostly it's just shoot folks. There's not a lot of platform
               jumping, just moving from door to door, ammo cache to ammo cache. The puzzle aspect
               of killing is limited. Mostly zombies lunge and beasts run at you. There's no puzzle-strategy
               on how to kill them - circle-strafe, rinse, repeat. Doom 3 has great object physics,
               but not nearly enough objects available to show it all. When you go to Hell later
               in the game, it's just red-red-red and there's even less to interact with.&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B0000A1VER/diabeticbooks"&gt;FarCry&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               FarCry is also not big on puzzles. There are a number of doors to open and forts to
               blow up. This is a much more tactical game - the "puzzle" factor is more "how do I
               kill as many of them before they realize there's just one of me." Sound (your footsteps)
               and light (your shadow) play a big part as you try to take out entire enclaves with
               limited ammo. The FarCry enemy AI is also top-notch and the best of the four games.
               The enemies will call for help, run away, panic, berzerk, hide, sneak and more. This
               makes you feel like you're fighting another intelligence. The physics model is without
               par, but none of the puzzles use it. There are a number of single-player downloadable
               maps that are&amp;nbsp;specifically&amp;nbsp;designed to show off the physics by&amp;nbsp;causing
               things like chain-reaction&amp;nbsp;blowing up of barrels, but I wish that kind of stuff
               was in the game more.&amp;nbsp;&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006I02Z/diabeticbooks"&gt;Half-Life 2&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               The puzzles in Half-Life 2 are a freakin' blast. Most are physics-based&amp;nbsp;which
               is great considering that I dig physics, and the physics engine within the game is
               fantastic. You'll find creative ways to raise water levels, set up ramps, remember
               that different objects have decidedly different weight, including your own body. There
               are gravity puzzles, water puzzles, 'how do I get up there' puzzles. Additionally
               you are, more often than not, presented with more than one way to solve the puzzle,
               but often only one solution is possible. Afterwards you'll find yourself saying, "oh,
               I can totally see where I took a wrong turn on that one."&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00008J7NZ/diabeticbooks"&gt;Halo 2&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               Halo 2 is a little weak on puzzles. Again, it's more tactical. Some fights you can
               bow out of by letting the fighting factions beat themselves up. Each enemy has a weakness
               or weapon they are the most vulnerable to, so there's a lot of rock-paper-scissors
               choosing of weapons. Most puzzles involve killing something then finding a button
               to open a door or move an object. Since your own interaction with the world is the
               "action" button, and that button can only "do stuff," you can only perform actions
               that an object is scripted to know.&lt;/td&gt;
         &lt;/tr&gt;
      &lt;/tbody&gt;
   &lt;/table&gt;
&lt;/p&gt;
&lt;p align=left&gt;
   &lt;strong&gt;Vehicles&lt;/strong&gt;
&lt;/p&gt;
&lt;p align=left&gt;
   &lt;strong&gt; 
   &lt;table border=1&gt;
      &lt;tbody&gt;
         &lt;tr&gt;
            &lt;th&gt;
               Game&lt;/th&gt;
            &lt;th&gt;
               My Thoughts&lt;/th&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006C2HA/diabeticbooks"&gt;Doom 3&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               No vehicles in the shipped game. Lame. However, &lt;a href="http://www.iddevnet.com/doom3/"&gt;just
               days ago vehicle support was added to the Mod SDK&lt;/a&gt; which means total-conversion
               mods could utilize vehicles soon.&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B0000A1VER/diabeticbooks"&gt;FarCry&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               &lt;p align=left&gt;
                  The &lt;a href="http://www.farcry-thegame.com/uk/vehicles.php"&gt;vehicles&lt;/a&gt; in FarCry
                  are wide ranging, from a blow-up boat, to a hang-glider, to buggies and jeeps. There
                  are number of times when you have to make smart use of a vehicle or its weaponry to
                  solve a task. FarCry and Halo 2 are just about equal when it comes to coolness of
                  vehicles, but Halo 2 gets the nod for including "jacking" of vehicles.
               &lt;/p&gt;
            &lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006I02Z/diabeticbooks"&gt;Half-Life 2&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               The "water hazard" sequence in Half-Life 2 is bar-none the most extraordinary experience
               I've ever had playing a single player FPS. It alone makes the game worth the price.
               Half-Life's vehicle use is great, and the immense size of the vehicles and beasts
               that the enemy uses is also awe-inspiring, especially the &lt;a href="http://www.download.com/Half-Life-2-Strider-movie/3000-7453_4-10288634.html"&gt;Striders&lt;/a&gt;.&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00008J7NZ/diabeticbooks"&gt;Halo 2&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               Halo 2 improves on Halo's use of vehicles which was already outstanding. Halo 2 adds
               the ability to "jack" a vehicle. With good timing you can jump onto an enemy vehicle
               and yank the driver out, throwing them from the cockpit. You then take over driving
               and, well, kill them all. There are also some&amp;nbsp;immense non-drivable vehicles that
               you have to jump on top off from a bridge and destroy from the inside. Also, the vehicle
               sizes far greatly from tanks to small "ghosts" which dramatically changes the feel
               of the game during these sequences. The tank sequences are especially powerful and
               satisfying.&lt;/td&gt;
         &lt;/tr&gt;
      &lt;/tbody&gt;
   &lt;/table&gt;
   &lt;/strong&gt;
&lt;/p&gt;
&lt;p align=left&gt;
   &lt;strong&gt;Graphics&lt;/strong&gt;
&lt;/p&gt;
&lt;p align=left&gt;
   &lt;table border=1&gt;
      &lt;tbody&gt;
         &lt;tr&gt;
            &lt;th&gt;
               Game&lt;/th&gt;
            &lt;th&gt;
               My Thoughts&lt;/th&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006C2HA/diabeticbooks"&gt;Doom 3&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               Touted as the graphics to end all graphics, Doom 3&amp;nbsp;is pretty snazzy. However,
               it's dark. Frankly I found myself thinking "are the graphics really all that good
               or are they justing being smart with shadows." The objects are gorgeous, as are the
               player models, and the use of light (what light there is) is a amazing. Everything
               casts a realistic shadow and the reflections and use of glass is amazing. It's just
               so damn dark. Additionally, the graphics are repetitive. When you've see one lonely
               Mars base level you've seen them all. OK, I get it. Doesn't the Sun come out on Mars?
               FYI: I play Doom 3 at 1280x1024x32 with 2x Anti-AliASINg. [&lt;a href="http://www.battle-fields.com/webimage/topimgs/doom3_18.jpg"&gt;Example
               Image&lt;/a&gt;]&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B0000A1VER/diabeticbooks"&gt;FarCry&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               I play FarCry at 1600x1200x32 with no Anti-AliASINg and it's amazing. The FarCry environment
               is largely outside on a tropical island. The organic aspect of the island is&amp;nbsp;well&amp;nbsp;represented
               with their graphics engine,&amp;nbsp;with the grass and trees standing out particularly
               well. The use of wind and sound along with swaying grass and foliage is&amp;nbsp;strong
               in the jungle scenes. However, when you start your way into the&amp;nbsp;caves and start&amp;nbsp;fighting
               monsters, it gets too dark and too much like&amp;nbsp;Doom 3. Frankly, I played FarCry
               religiously for days until I got to the&amp;nbsp;dark&amp;nbsp;monster stuff, and just got
               disinterested. I'd go back and play the game from the start up through, and until,
               the monster levels. Make sure your resolution is&amp;nbsp;as high as your card will support,
               it's worth losing a few frames a second to get a glimpse at the incredibly long draw-depth.
               FarCry boasts a draw-depth (the distances at which objects in the environment aren't
               rendered anymore) as much as a full kilometer. The levels in FarCry are MASSIVE -
               as much as 4 kilometers square. The engine really shines when you are at the top of
               the island with a sniper rifle. The binoculars are a thrill to use to spy on the enemy
               at long distances. [&lt;a href="http://pcmedia.ign.com/pc/image/farcry_012004_009.jpg"&gt;Example
               Image&lt;/a&gt;]&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006I02Z/diabeticbooks"&gt;Half-Life 2&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               &lt;p align=left&gt;
                  Half-Life 2 blew me away.&amp;nbsp;As much as Doom 3&amp;nbsp;floored me, Half-Life 2 crushed
                  Doom 3. Argue polygons and detail and lighting and whatever all you want, but when
                  Half-Life&amp;nbsp;2 renders an entire living city-scape with clotheslines and giant propaganda-filled
                  TV overloading city squares, and waterways filled with floating plastic bottles (that
                  you can interact with) the 10x10 corridors and mazes that Doom 3 has me running around
                  in just can't compete. Additionally the &lt;a href="http://pcmedia.gamespy.com/pc/image/article/552/552906/half-life-2-20041001075518411.jpg"&gt;face
                  and character modeling &lt;/a&gt;is without par. Half-Life 2 has restored my faith in PC
                  gaming. [&lt;a href="http://image.com.com/gamespot/images/2004/screen0/914642_20041116_screen012.jpg"&gt;Example
                  Image&lt;/a&gt;]
               &lt;/p&gt;
            &lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00008J7NZ/diabeticbooks"&gt;Halo 2&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               The Halo graphics&amp;nbsp;engine has been completely&amp;nbsp;re-written&amp;nbsp;between Halo
               1 and Halo 2. It appears to be a progressive rendering image that drops textures and
               polygon count when frame rate might suffer.&amp;nbsp; For example, when a level loads,
               it loads immediately, but you can see far-away textures load last and cover over low-res
               images and low polygon count buildings. You can still move around during these times,
               and it rarely lasts more than second, but I thought it was of note. Additionally as
               you move away from, say a dead body on the ground that is not longer of interest,
               there is a "popout" (my word) effect as the game dramatically and quickly lowers the
               polygon count (or swaps the model) for that entity, presumably to open up processing
               power for more important objects. I personally find this effect distracting and obvious,
               but no one else I've mentioned it to seems to care.&amp;nbsp; During a slow moment, look
               at any object and walk slowly towards it and then away from it as far as you can.&amp;nbsp;
               You'll be able to count at least THREE, possibly FOUR separate models or "steps" that
               the object will go through.&amp;nbsp; Again, I'm assuming that since the XBox is nearly
               three-year-old technology running an &lt;a href="http://www.vanshardware.com/articles/2001/november/011116_Xbox/011116_Xbox.htm"&gt;NVidia
               nForce derived card&lt;/a&gt;&amp;nbsp;that this software technique&amp;nbsp;opened up&amp;nbsp;processing
               headroom for normal mapping.&amp;nbsp;To be clear, the graphics in Halo 2 are the greatest
               graphics I've ever seen from a console, and certainly make standard TV shine. (Halo
               2 also shines at 480p on a HDTV but 480 horizontal lines is the max, and equivalent
               to 640x480 or 720x480 resolution) However, it can't compete with a 19" LCD at 1600x1200
               running Half-Life 2. [&lt;a href="http://media.teamxbox.com/games/ss/472/1099797901.jpg"&gt;Example
               Image&lt;/a&gt;]&lt;/td&gt;
         &lt;/tr&gt;
      &lt;/tbody&gt;
   &lt;/table&gt;
&lt;/p&gt;
&lt;p align=left&gt;
   &lt;strong&gt;Level Design&lt;/strong&gt;
&lt;/p&gt;
&lt;p align=left&gt;
   &lt;strong&gt; 
   &lt;table border=1&gt;
      &lt;tbody&gt;
         &lt;tr&gt;
            &lt;th&gt;
               Game&lt;/th&gt;
            &lt;th&gt;
               My Thoughts&lt;/th&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006C2HA/diabeticbooks"&gt;Doom 3&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               I found the level design in Doom 3 to be fairly pedestrian. I mean pedestrian in both
               meanings. It's combines the excitement&amp;nbsp;(not) of overly-symmetrical design with
               the thrill (not)&amp;nbsp;of constantly being on-foot, not to mention having to back-track
               to retrieve keys and widgets you may have missed. The levels tend to be named Alpha
               Lab 1, which isn't a bad name until you've been playing for hours and the next level
               is Alpha Lab 7. OK, I get it. Can I get to the freakin' Beta lab? Ah, steel walls
               with no lights.&amp;nbsp;We've made it to Mars, but didn't bring backup batteries? Flares?
               A friggin' glowstick? But, I digress. Every once in a while you get to leave the lab
               for the Martian landscape, but you consistently don't bring an air pack or helmet
               so you only get to enjoy the scenery for 20 seconds before your brain explodes. You
               have to run as fast as you can to the other airlock. Again, we knew we were coming
               to Mars. Perhaps a breezeway would have been a nice architectural touch? Just a though.&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B0000A1VER/diabeticbooks"&gt;FarCry&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               Levels in FarCry are many and varied. The game is huge, and while most of it happens
               on a remote tropical island, the design makes good use of caves, mountain trails,
               forts, underwater&amp;nbsp;and boat approaches, as well as the best level that includes
               a giant abandoned tanker (I thought this level was reminiscent of The Goonies. Go
               figure.) culminating in a huge fire-fight on the top that includes helicopters and
               guys on turrets. And me with a single Uzi. That was a tough one.&amp;nbsp; As you move
               deeper there are levels in underground caves, high in the trees&amp;nbsp;(ala Ewok village)
               and reinforced concrete forts. If it wasn't for those darn monsters, I would have
               loved it all the way through. I just don't feel the need to put genetically-modified
               mutant creatures in every single game.&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006I02Z/diabeticbooks"&gt;Half-Life 2&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               That said, Half-Life 2 is all about mutant creatures (from another dimension?) but
               the Level Design is perfect. You have to think though, when moving around these levels.
               While the gameplay is pretty linear, there are &lt;em&gt;many&lt;/em&gt;
   &lt;/strong&gt; back roads and alleys that should be explored, not only get to useful plot
   points, but to avoid running out of health. There's little backtracking, but when
   there is, you'll often find different things and people when you return to a previous
   location. I got nailed a couple of times assuming that I'd cleared an area, when of
   course, in a realistic simulation, the cops would come to check out the commotion
   and might be waiting for my return. There is an uncomfortable break in the action
   as you move from level to level. It presents itself as a mandatory pause with a -loading-
   sign. After 20 seconds the game continues. I wish they'd have been loading these levels
   in a background thread as Halo 2 does. Otherwise, Half-Life 2 is the closest thing
   I've experienced to total immersion in a game. You are truly "playing a movie." I
   feel that the total lack of cut-scenes increases this sense of immersion. Instead
   the scripted encounters take the place of cut-scenes and you always have control over
   your character's movement.&gt;
   &gt;
   &lt;strong&gt; 
   &lt;tr&gt;
      &lt;td&gt;
         &lt;a href="http://www.amazon.com/o/ASIN/B00008J7NZ/diabeticbooks"&gt;Halo 2&lt;/a&gt;&lt;/td&gt;
      &lt;td&gt;
         Halo 2 level design is, as usual, stunning. It's a little two symmetrical and repetitive,
         IMHO, when you encounter the Covenant and enter their domain. However, the early city
         levels are massive. Another important note about levels - in Halo 2 there isn't the
         sense of a distinct "level," as there are "scenes." There is no loading pause to speak
         of as you move from location to location. You'd think at this level of the development
         of games as a media, the publishers would realize that we don't like waiting for levels
         to load. If you know the game is linear, then you know what the next level is. For
         Pete's sake, preload it as I'm moving towards it! It's not like I'm moving towards
         another level. Halo 2 takes this Common Sense to heart and gives you a completely
         seamless experience. 
      &lt;/td&gt;
   &lt;/tr&gt;
   &gt;&gt;
   &lt;/strong&gt;
&lt;/p&gt;
&lt;p align=left&gt;
   &lt;strong&gt;Multiplayer&lt;/strong&gt;
&lt;/p&gt;
&lt;p align=left&gt;
   &lt;table border=1&gt;
      &lt;tbody&gt;
         &lt;tr&gt;
            &lt;th&gt;
               Game&lt;/th&gt;
            &lt;th&gt;
               My Thoughts&lt;/th&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006C2HA/diabeticbooks"&gt;Doom 3&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               Doom 3 only supports up to 4 players at a time to play multiplayer.&amp;nbsp;In my mind,
               this is hardly multiplayer. If I want to play an FPS with strangers, I'd rather it
               be a free-for-all 16 player war than&amp;nbsp;just&amp;nbsp;3 other schleps. There are hacks
               and mods to allow for more players, but this&amp;nbsp;was a surprising message for ID
               to be sending the&amp;nbsp;public about their flagship product.&amp;nbsp;Doom 3 is clearly
               meant to be a single player game.&amp;nbsp;&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B0000A1VER/diabeticbooks"&gt;FarCry&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               FarCry has a very active multiplayer map community and there are literally scores
               of maps available. The interface is slightly less friendly than Counter-Strike, and
               certainly not as flexible as Halo 2, but still a strong multi-player contender, and
               the winner for massively-sized maps.&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006I02Z/diabeticbooks"&gt;Half-Life 2&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               Half-Life 2 is officially a single player game. It does ship with multiplayer maps,
               but as has been the tradition since Counter-Strike (a total conversion Half-Life 1
               mod), the engine is meant to be reused for multiplayer. That said, when you buy Half-Life
               2 via Steam, you get the full version of Counter-Strike: Source, which is newer port
               of the anti-terrorist classic Counter-Strike using the new "Source" Graphics Engine
               used in Half-Life 2. This game is a blast and includes lots of maps, weapons and VoIP
               trash talking.&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00008J7NZ/diabeticbooks"&gt;Halo 2&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               Halo 2 along with XBox Live redefines ease-of-use with its multiplayer. There are
               Parties, Clans, Rumbles, Giant Fights, Little Fights and in-between. You can use any
               of their dozen included game variants with complete control over allowed weapons,
               rules, etc. You can also create named-variants of your own games. Every single game
               played is stored and can be accessed via Bungie.Net or RSS Feeds. Additionally, everyone
               who has XBox Live has an XBox Communicator Microphone and broadband (required) so
               the sense of multi-player community is heightened by both proximity-based communication
               (whoever is nearby can hear you) and push-to-talk walkie-talkie communication (press
               a button and talk through your helmet to your team). The XBox has really improved
               multiplayer gaming with the inclusion of microphones in a way that is possible, but
               still a hassle, on the PC.&lt;/td&gt;
         &lt;/tr&gt;
      &lt;/tbody&gt;
   &lt;/table&gt;
&lt;/p&gt;
&lt;p align=left&gt;
   &lt;strong&gt;Patch-ability/Maintain-ability&lt;/strong&gt;
&lt;/p&gt;
&lt;p align=left&gt;
   &lt;table border=1&gt;
      &lt;tbody&gt;
         &lt;tr&gt;
            &lt;th&gt;
               Game&lt;/th&gt;
            &lt;th&gt;
               My Thoughts&lt;/th&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006C2HA/diabeticbooks"&gt;Doom 3&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               There's an Update button within Doom 3, but it didn't tell me I needed to update even
               though an update was clearly available not sure what's up with that.&amp;nbsp; Additionally,
               when I did update, the new update wouldn't allow me to use my own save games from
               where they were saved. Instead I had to start that level over from the beginning.
               I'm sure there was a technical reason why this had to happen, but it was LAME.&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B0000A1VER/diabeticbooks"&gt;FarCry&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               FarCry has had some patching troubles with an abortive attempt at a Patch version
               1.2 that was yanked the following day (not after I and many others installed it.)
               Version 1.3 took months to be released.&amp;nbsp; There's no patch notification service
               so I have to poll for patches, and they are installed via InstallShield. Fairly typical,
               certainly not revolutionary, and one of the lame things about PC gaming. I also had
               to start a level over due to file version incompatibilities.&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006I02Z/diabeticbooks"&gt;Half-Life 2&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               Half-Life 2 uses a unique game-delivery system called &lt;a href="http://www.steampowered.com/"&gt;Steam&lt;/a&gt;.
               I payed&amp;nbsp;$70 and received not only Half-Life 2, but also the original Half-Life,
               Counter Strike:Source, and 10 additional games like Day Of Defeat and Team Fortress.
               All delivered over Steam. I can even play them on my laptop just by installing Steam
               and logging in. All the patches are automatically installed on startup.&amp;nbsp; Some
               folks complain that you have to be online to get your purchase authenticated, but
               that hasn't been a problem for me, and I was totally impressed as the multi-gigabyte
               Half-Life 2 purchase was slowly pre-loaded onto my machine weeks before the game was
               released. The entire purchase and experience was online. No box, no problems. I was
               throughly impressed with the process. Steam also checks the version of your Video
               Card Driver and points you to the correct download page to get the latest version.
               Why doesn't Windows Update open their API to do that for the OEMs?&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00008J7NZ/diabeticbooks"&gt;Halo 2&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               Surprisingly patching XBox Live is not a seamless as Half-Life 2/Steam. With Steam,
               you don't have to do a single thing. With the XBox you are informed there is a required
               updated and have to press one button. Considering that I don't have a choice, why
               not just install it silently? That said, every update experience (what few there are)
               I've had with the Xbox has been butter. You just hit "A" and get on with it. One of
               the nice things about Console Gaming, but as has been proven with Steam, a good experience
               is equally possible with the PC.&lt;/td&gt;
         &lt;/tr&gt;
      &lt;/tbody&gt;
   &lt;/table&gt;
&lt;/p&gt;
&lt;p&gt;
   &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/p&gt;
&lt;p align=left&gt;
   &lt;table border=1&gt;
      &lt;tbody&gt;
         &lt;tr&gt;
            &lt;th&gt;
               Hanselman 
               &lt;br&gt;
               Rank&lt;/th&gt;
            &lt;th&gt;
               Game&lt;/th&gt;
            &lt;th&gt;
               My Thoughts&lt;/th&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006I02Z/diabeticbooks"&gt;&lt;strong&gt;Half-Life
               2&lt;/strong&gt;&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               Great graphics, great puzzles, great story, great feel, great experience. Steam rocks
               with auto-updates and patching. My favorite and the ultimate FPS PC game so far.&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00008J7NZ/diabeticbooks"&gt;&lt;strong&gt;Halo 2&lt;/strong&gt;&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               Unparalleled totally seamless multiplayer with up to 16 folks trash talking simultaneously,
               a dozen variations, best graphics on a console, no patching, no worries, downloadable
               levels and &lt;a href="http://www.hanselman.com/blog/permalink.aspx?guid=" 4deb3ddd-8211-46fc-9cef-f6154785c1fe??&gt;unbelievable
               statistical database&lt;/a&gt;. 
            &lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B0000A1VER/diabeticbooks"&gt;&lt;strong&gt;FarCry&lt;/strong&gt;&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               If you want to fight on a tropical island with hundreds of terrorists, this is a winner.
               Also has easy multiplayer with massive maps and dozens more to download. Also the
               total-conversion mod community is large and we will likely see the next big mod come
               from this group for this game.&lt;/td&gt;
         &lt;/tr&gt;
         &lt;tr&gt;
            &lt;td&gt;
               &lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
            &lt;td&gt;
               &lt;a href="http://www.amazon.com/o/ASIN/B00006C2HA/diabeticbooks"&gt;&lt;strong&gt;Doom 3&lt;/strong&gt;&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;
               Only 4 players in multiplayer? Oy. Too dark, too scary, a real disappointment. Amazing
               sound, truly, but otherwise I just don't have the patience or stomach for the repetition.&lt;/td&gt;
         &lt;/tr&gt;
      &lt;/tbody&gt;
   &lt;/table&gt;
&lt;/p&gt;
&gt;&lt;img width="0" height="0" src="http://www.hanselman.com/blog/aggbug.ashx?id=98bd0e23-a0de-476d-a62a-ea2a614045b3"&gt;</description>
      <comments>http://www.hanselman.com/blog/CommentView.aspx?guid=98bd0e23-a0de-476d-a62a-ea2a614045b3</comments>
      <category>Musings</category>
    </item>
  </channel>
</rss>