﻿<?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.n