<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>PHP vs .Net &#187; morgan</title>
	<atom:link href="http://www.phpvs.net/author/morgan/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.phpvs.net</link>
	<description>ASP.Net and PHP go head to head</description>
	<lastBuildDate>Thu, 01 Jul 2010 05:52:22 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Manually validate an ASP.Net MVC form on the client side with MicrosoftMvcValidation.js and jQuery</title>
		<link>http://www.phpvs.net/2010/04/26/manually-validate-an-asp-net-mvc-form-on-the-client-side-with-microsoftmvcvalidation-js-and-jquery/</link>
		<comments>http://www.phpvs.net/2010/04/26/manually-validate-an-asp-net-mvc-form-on-the-client-side-with-microsoftmvcvalidation-js-and-jquery/#comments</comments>
		<pubDate>Tue, 27 Apr 2010 06:16:51 +0000</pubDate>
		<dc:creator>morgan</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[AJAX]]></category>
		<category><![CDATA[ASP.Net]]></category>
		<category><![CDATA[ASP.Net MVC]]></category>
		<category><![CDATA[asp.net asp.net-mvc jquery validation]]></category>

		<guid isPermaLink="false">http://www.phpvs.net/?p=196</guid>
		<description><![CDATA[A recent problem cropped up in my Asp.Net MVC application.  Its using the standard setup of DataAnnotations + MicrosoftMvcValidation.js + jQuery 1.4.2, and I needed to check the validation state of a form before performing some client-side actions. No problem, right?
Obviously not.
This second part of this post gets in depth as to what&#039;s going [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignleft size-full wp-image-213" title="check-x" src="http://www.phpvs.net/wp-content/uploads/2010/04/check-x.png" alt="Validation" width="171" height="165" />A recent problem cropped up in my Asp.Net MVC application.  Its using the standard setup of DataAnnotations + MicrosoftMvcValidation.js + jQuery 1.4.2, and I needed to check the validation state of a form before performing some client-side actions. No problem, right?</p>
<p>Obviously not.</p>
<p>This second part of this post gets in depth as to what&#039;s going on with the MicrosoftMvcValidation script, but to save you some time, I&#039;ll post the solution first.</p>
<p><span style="text-decoration: underline;"><strong>To manually validate your form with MicrosoftMvcValidation.js:</strong></span></p>
<p><del datetime="2010-07-01T05:45:10+00:00">In MicrosoftMvcValidation.js, change line 20 from:</p>
<p style="padding-left: 30px;"><code> return Sys.Mvc._ValidationUtil.$0($2.validate('submit'));})); return $2;</code></p>
<p>to</p>
<p style="padding-left: 30px;"><code> return Sys.Mvc._ValidationUtil.$0($2.validate('submit'));})); <strong>$0.MvcValidationFormContext = $2;</strong> return $2;</code></p>
<p>Alternately, if you&#039;re using the debug version of the script, you can achieve the same effect by adding the following to line 196 (the end of the _parseJsonOptions function):</p>
<p style="padding-left: 30px;"><code>formElement.MvcValidationFormContext = formContext;</code></p>
<p></del></p>
<p><strong>UPDATE: </strong> As Morten Christiansen points out in the comments, there is a much cleaner way of accessing the FormContext object, without having to introduce a custom tracking property and modifying the script.  Instead of a custom property, we can just use<br />
<code>$('form')[0]['__MVC_FormValidation']</code>.  Thanks to Morten for pointing this out!</p>
<p>Now we can use the following jQuery/javascript code to manually validate our form:</p>
<pre>
var $form = ("#MyForm");                            // Select our form with jQuery
<del datetime="2010-07-01T05:45:10+00:00">var context = $form[0].MvcValidationFormContext;    // Access the new property we created</del>
var errors;
if ($form[0]['__MVC_FormValidation']) {
    errors = $form[0]['__MVC_FormValidation'].validate("submit");        // Validate the form
}
if (!$form[0]['__MVC_FormValidation'] || errors.length == 0) {
    // No errors, do your stuff
}
</pre>
<hr />
Now for the explanation.</p>
<p>I assumed (incorrectly) that there must be a client-side API to <code>MicrosoftMvcValidation.js</code>, the javascript responsible for dynamic client side form validation that ships with the ASP.Net MVC framework.  Unfortunately, in all my digging, I could not unearth one -- and it seems like a huge oversight.  The amount of effort to expose an <code>isValid</code> property or a <code>validate()</code> function on the client would be pretty minimal!</p>
<p>Why would you need to do this?  Doesn&#039;t the validation occur automatically?   Well, yes it does -- when you submit the form, or click around in it.  However, there are lots of cases where you might want to manually trigger the error messages or perform a client-side action based on whether or not the form is valid, without running the submit handler.   In my case, I wanted to make sure the form was valid <em>before </em>trying to submit it, as our ajax pipeline puts up the &#034;spinner&#034; graphic when a submit event is triggered, which meant it was flashing briefly and looked dumb.</p>
<p>The most common response I ran across when searching for how to manually validate was -- <a href="http://stackoverflow.com/questions/2060554/asp-net-mvc-check-form-input-is-valid-on-submit">give up and use the jQuery validate plugin</a>.  This would be my preferred solution to be honest, but I ran into at least two blockers with jQuery validate:</p>
<ol>
<li> it doesn&#039;t seem to work with modal dialogs generated from jQuery UI,</li>
<li> it doesn&#039;t seem to work with forms that are loaded into the document via an ajax call.</li>
</ol>
<p>So that was out.  Since I already had most of what I needed working with the Microsoft scripts, I went back to them and started exploring the code to see if I could discover any sort of public API.  This is what I came up with.</p>
<p>The key thing that I found was that <code>MicrosoftMvcValidation</code> creates a javascript object called a <code>FormContext</code>, which has a <code>validate(eventName)</code> method.  This <em>seemed </em>promising, so I tried following the code to see how I could get at this validate method. Well -- I couldn&#039;t.  Not without some modifications.  Here&#039;s how it works.</p>
<p>When you include <code>MicrosoftMvcValidation</code>, the main piece of script that executes is this:</p>
<pre>Sys.Mvc.FormContext._Application_Load = function Sys_Mvc_FormContext$_Application_Load() {
    var allFormOptions = window.mvcClientValidationMetadata;
    if (allFormOptions) {
        while (allFormOptions.length &gt; 0) {
            var thisFormOptions = allFormOptions.pop();
            Sys.Mvc.FormContext._parseJsonOptions(thisFormOptions);
        }
    }
}
</pre>
<p>Adding <code>&lt;% Html.EnableClientValidation(); %&gt;</code> to your views causes a bunch of JSON data to be output to the page, and appended to the <code>window.mvcClientValidationMetatdata</code> javascript object.  When the page is ready, the above function runs and calls <code>FormContext._parseJsonOptions()</code> on all the rules and data that were output to that object.</p>
<p><code>_parseJsonOptions </code>is what creates the <code>FormContext </code>object that we&#039;re interested in.  In fact, the return value of <code>_parseJsonOptions </code><em>is the FormContext</em>&#8230; but sadly, Application_Load ignores the return value, and it&#039;s just thrown to the bitbucket, never to be seen again (at least by us).</p>
<p>Judging from the underscores on the function names, it&#039;s pretty clear that these are meant to be internal operations, so we can (perhaps) excuse them for not storing and exposing the <code>FormContext </code>for us. From the framework&#039;s point of view, it doesn&#039;t need to be stored anywhere, because it still has it -- <code> _parseJsonOptions</code> internally adds new event handlers for the form, and these handler delegates close over the <code>FormContext </code>object.  The closures means that internally, the form handlers still have a saved reference to what they need, so the application load function doesn&#039;t need to do anything with the return value.  The <code>FormContext </code>never surfaces -- so if we want to validate the form ourselves, we need to <del datetime="2010-07-01T05:47:53+00:00">expose</del> dig for it.</p>
<p><del datetime="2010-07-01T05:47:53+00:00">All that my code at the top of the post is doing is modifying the <code>_parseJsonOptions</code> function (minified to be named <code>$12</code>), to start adding a new property to the form element in the DOM, which will store the created <code>FormContext</code> object. I named this property <code>MvcValidationFormContext</code>, but you could call it anything you&#039;d like.  You can subsequently access this new property to get the <code>FormContext </code>and call <code>validate("submit")</code> on it, which fires the validation as though we were trying to submit the form, and returns a collection of errors we can check.</del></p>
<p>As Morten pointed out, the reference is, of course, still there.  You can access the closed over FormContext by grabbing the DOM element and digging in it&#039;s properties array.  The updated code reflects this.</p>
<hr />I&#039;d love to see an upgrade to <code>MicrosoftMvcValidation.js</code> to include a client API in the future.  Even more, I&#039;d love to see <a href="http://bassistance.de/jquery-plugins/jquery-plugin-validation/">jQuery Validate</a> get some attention to fix the blockers that I ran into, so I can dump the MicrosoftAjax scripts out of my project altogether.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpvs.net/2010/04/26/manually-validate-an-asp-net-mvc-form-on-the-client-side-with-microsoftmvcvalidation-js-and-jquery/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>ASP.Net MVC &#8211; How to route to images or other file types</title>
		<link>http://www.phpvs.net/2009/08/06/aspnet-mvc-how-to-route-to-images-or-other-file-types/</link>
		<comments>http://www.phpvs.net/2009/08/06/aspnet-mvc-how-to-route-to-images-or-other-file-types/#comments</comments>
		<pubDate>Fri, 07 Aug 2009 04:23:51 +0000</pubDate>
		<dc:creator>morgan</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[ASP.Net]]></category>
		<category><![CDATA[ASP.Net MVC]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[MVC]]></category>

		<guid isPermaLink="false">http://www.phpvs.net/?p=123</guid>
		<description><![CDATA[A recent question on Stack Overflow (and subsequent answer that I wrote for it) inspired this post.  I had recently been discussing URL rewriting in depth with my brother, and have also been doing some introductory work with the routing engine in ASP.Net MVC, and the question piqued my interest since I had been [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.phpvs.net/wp-content/uploads/2009/08/Image.png"><img class="alignright size-full wp-image-228" style="border: 0pt none;" title="Image" src="http://www.phpvs.net/wp-content/uploads/2009/08/Image.png" alt="" width="256" height="256" /></a>A <a href="http://stackoverflow.com/questions/1146652/how-do-i-route-images-using-asp-net-mvc-routing">recent question on Stack Overflow</a> (and subsequent answer that I wrote for it) inspired this post.  I had recently been discussing URL rewriting in depth with my brother, and have also been doing some introductory work with the routing engine in ASP.Net MVC, and the question piqued my interest since I had been meaning to look at this more closely for some time.</p>
<p>The question on Stack Overflow is titled &#034;How do I route images with ASP.Net MVC&#034;, but fundamentally the question is really asking &#034;<strong>how can I use ASP.Net MVC to re-route URL&#039;s to actual physical files, rather than methods of a controller?</strong>&#034;</p>
<p>To be clear, lets address the conceptual differences between routing and url rewriting.  Url rewriting takes the requested URL and modifies it before your code ever sees it.  As far as your application is concerned, the client requested the rewritten URL.  All that URL rewriting does is to change one URL into another URL, based on pattern matching.</p>
<p>Routing is a different and much more powerful beast.  The ASP.Net routing engine maps an URL to a &#034;resource&#034;, based on a set of routes.  The first route to match the requested URL wins the prize, and sends the request off to the resource it chooses.  For the ASP.Net MVC framework (which uses <code>System.Web.Routing</code> under the hood), a resource is something that can handle the request object, which is always a piece of code.</p>
<p>So where does that leave physical files?  If a request is always parsed by the routing engine and then handed off to some function somewhere, how can we ever route a request for an image to actually return the physical image?</p>
<p>Well, it takes a tiny bit of legwork, but once we&#039;re through it, I&#039;m confident you will see the huge advantages that routing has over simple url-rewriting.  We will show the equivalent of url-rewriting by handling a request for an image using an URL that doesn&#039;t map to a physical path, but be able to return the image anyway.</p>
<h2>Handling the Request</h2>
<p>First off, we need to handle the request that we want to re-route to a physical file.  Out of the box, ASP.Net MVC uses an instance of the <code>MvcRouteHandler </code>object to handle every request.  <code>MvcRouteHandler </code> hides all the complexities of taking the requested URL, breaking it down into parts, finding the right controller in your application, instantiating it and passing it all the data it needs.</p>
<p>The end result of <code>MvcRouteHandler </code>is not what we desire. We want to return an image, not instantiate a controller and run a method.   We want to skip dealing with controllers altogether in this case.  So lets create our own route handler that we&#039;ll use instead.</p>
<p>To do so, we simply implement <code>IRouteHandler</code>, an interface exposed by ASP.Net MVC that actually inherits from <code>IHttpHandler</code>.  This means that what we&#039;re writing is the ASP.Net MVC equivalent of an .ashx file for a webforms app -- we&#039;re inserting our own handling module into the ASP.Net pipeline, that will handle the request much closer to the webserver/http level, rather than at the ASP.Net application level.</p>
<p><code>IRouteHandler </code>only has one method that we need to implement, which is <code>GetHttpHandler()</code>.</p>
<pre class="prettyprint"><code><span class="kwd">using</span><span class="pln"> </span><span class="typ">System</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="typ">Collections</span><span class="pun">.</span><span class="typ">Generic</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="pln">IO</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="typ">Linq</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="typ">Web</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="typ">Web</span><span class="pun">.</span><span class="typ">Compilation</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="typ">Web</span><span class="pun">.</span><span class="typ">Routing</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="typ">Web</span><span class="pun">.</span><span class="pln">UI</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">namespace</span><span class="pln"> MvcApplication1
</span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">ImageRouteHandler</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">IRouteHandler</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">IHttpHandler</span><span class="pln"> </span><span class="typ">GetHttpHandler</span><span class="pun">(</span><span class="typ">RequestContext</span><span class="pln"> requestContext</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">string</span><span class="pln"> filename </span><span class="pun">=</span><span class="pln"> requestContext</span><span class="pun">.</span><span class="typ">RouteData</span><span class="pun">.</span><span class="typ">Values</span><span class="pun">[</span><span class="str">"filename"</span><span class="pun">]</span><span class="pln"> </span><span class="kwd">as</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">;</span><span class="pln">

            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">string</span><span class="pun">.</span><span class="typ">IsNullOrEmpty</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">))</span><span class="pln">
            </span><span class="pun">{</span><span class="pln">
                </span><span class="com">requestContext.HttpContext.Response.Clear();
                requestContext.HttpContext.Response.StatusCode = 404;
                requestContext.HttpContext.Response.End();
</span><span class="pln">            </span><span class="pun">}</span><span class="pln">
            </span><span class="kwd">else</span><span class="pln">
            </span><span class="pun">{</span><span class="pln">
                requestContext</span><span class="pun">.</span><span class="typ">HttpContext</span><span class="pun">.</span><span class="typ">Response</span><span class="pun">.</span><span class="typ">Clear</span><span class="pun">();</span><span class="pln">
                requestContext</span><span class="pun">.</span><span class="typ">HttpContext</span><span class="pun">.</span><span class="typ">Response</span><span class="pun">.</span><span class="typ">ContentType</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">GetContentType</span><span class="pun">(</span><span class="pln">requestContext</span><span class="pun">.</span><span class="typ">HttpContext</span><span class="pun">.</span><span class="typ">Request</span><span class="pun">.</span><span class="typ">Url</span><span class="pun">.</span><span class="typ">ToString</span><span class="pun">());</span><span class="pln">

                </span><span class="com">// find physical path to image here.  </span><span class="pln">
                </span><span class="kwd">string</span><span class="pln"> filepath </span><span class="pun">=</span><span class="pln"> requestContext</span><span class="pun">.</span><span class="typ">HttpContext</span><span class="pun">.</span><span class="typ">Server</span><span class="pun">.</span><span class="typ">MapPath</span><span class="pun">(</span><span class="str">"~/test.jpg"</span><span class="pun">);</span><span class="pln">

                requestContext</span><span class="pun">.</span><span class="typ">HttpContext</span><span class="pun">.</span><span class="typ">Response</span><span class="pun">.</span><span class="typ">WriteFile</span><span class="pun">(</span><span class="pln">filepath</span><span class="pun">);</span><span class="pln">
                requestContext</span><span class="pun">.</span><span class="typ">HttpContext</span><span class="pun">.</span><span class="typ">Response</span><span class="pun">.</span><span class="typ">End</span><span class="pun">();</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">string</span><span class="pln"> </span><span class="typ">GetContentType</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> path</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Path</span><span class="pun">.</span><span class="typ">GetExtension</span><span class="pun">(</span><span class="pln">path</span><span class="pun">))</span><span class="pln">
            </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">case</span><span class="pln"> </span><span class="str">".bmp"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Image/bmp"</span><span class="pun">;</span><span class="pln">
                </span><span class="kwd">case</span><span class="pln"> </span><span class="str">".gif"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Image/gif"</span><span class="pun">;</span><span class="pln">
                </span><span class="kwd">case</span><span class="pln"> </span><span class="str">".jpg"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Image/jpeg"</span><span class="pun">;</span><span class="pln">
                </span><span class="kwd">case</span><span class="pln"> </span><span class="str">".png"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Image/png"</span><span class="pun">;</span><span class="pln">
                </span><span class="kwd">default</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span></code></pre>
<p>The above <code>IRouteHandler </code>is pretty simple.  Ignoring the <code>GetContentType </code>helper method, there&#039;s really only two things happening.  First, we check for a &#034;filename&#034; parameter that got passed in to our handler (more on that in a second).  If it&#039;s not there, we return a 404 response.  Otherwise, we attempt to open up the physical file &#034;test.jpg&#034;, and stream it to the browser.</p>
<p>Clearly, this should be adapted to your needs by actually using the filename parameter to find the physical files on your system.   But moving on -- how do we invoke this from our MVC app?  And how do we pass in the filename parameter, of which we&#039;d like to reroute to some other physical path?</p>
<h2>Routing the Request to the Custom Handler</h2>
<p>Well, this is the easy part.  Where you&#039;d normally define your routes in <code>Global.asax</code>, simply use <code>routes.Add()</code>, instead of <code>routes.MapRoute()</code>.  Just like this:</p>
<pre>routes.Add("ImagesRoute",
                 new Route("graphics/{filename}", new ImageRouteHandler()));</pre>
<p>This method of adding our route allows us to specify our custom <code>IRouteHandler</code>, rather than <code>routes.MapRoute()</code>, which by default uses an instance of <code>MvcRouteHandler</code>.  So now, we&#039;ve defined a route that matches against any requested URL containing &#034;graphics/&#034;, and puts the rest of the URL into the &#034;filename&#034; bucket of the <code>RouteDataDictionary</code>, and hands it off to our <code>IRouteHandler</code>.  This is how we pass the filename parameter into our custom route handler -- basically the same way we pass things into controllers, by defining the variables in the route pattern.</p>
<p>We&#039;ve successfully routed all URL&#039;s containing &#034;graphics/&#034;, which doesn&#039;t physically exist in our web application, and returning &#034;temp.jpg&#034;, which could exist anywhere.  With a bit of coding around the file IO, you could return files from anywhere.</p>
<p>And that&#039;s pretty much it!  You might be thinking, &#034;this seems like a lot of extra work just to re-route a URL to a physical file that already existed in my web app!&#034;.   If you take a step back though, you&#039;ll see the power of this approach.  What if you wanted to log every request to the original URL to a special log file?  What if you wanted to also transform the image before returning it?  Perhaps launch a system executable or asynchronously hit a web service?  What if you wanted to&#8230;?</p>
<p>In a nutshell, by inserting your own HttpHandlers into the ASP.Net pipeline to handle routed requests, you can code <em>anything that you&#039;d like to happen</em> when a request comes in, rather than just rewriting it to some other URL.</p>
<p><a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fwww.phpvs.net%2f2009%2f08%2f06%2faspnet-mvc-how-to-route-to-images-or-other-file-types%2f"><img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.phpvs.net%2f2009%2f08%2f06%2faspnet-mvc-how-to-route-to-images-or-other-file-types%2f&amp;bgcolor=FF9933&amp;cbgcolor=D4E1FD" border="0" alt="kick it on DotNetKicks.com" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpvs.net/2009/08/06/aspnet-mvc-how-to-route-to-images-or-other-file-types/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>.Net Mocking Frameworks &#8211; Capability Comparison</title>
		<link>http://www.phpvs.net/2009/04/25/net-mocking-frameworks-capability-comparison/</link>
		<comments>http://www.phpvs.net/2009/04/25/net-mocking-frameworks-capability-comparison/#comments</comments>
		<pubDate>Sun, 26 Apr 2009 06:04:40 +0000</pubDate>
		<dc:creator>morgan</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[Integration Testing]]></category>
		<category><![CDATA[Mocks]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[Unit Testing]]></category>

		<guid isPermaLink="false">http://www.phpvs.net/?p=80</guid>
		<description><![CDATA[A chart form summary of some of the features, capabilities and characteristics of four of the most popular mock object frameworks used for test driven development and design with .Net projects.]]></description>
			<content:encoded><![CDATA[<p>I have a couple years of experience of TDD under my belt, but it&#039;s only recently that I&#039;ve felt like I am a relatively decent practitioner of it.  I attribute this to forcing myself to take the plunge into mocking, and the knowledge of patterns and loosely-coupled design that I&#039;ve gained from it.</p>
<p>You see, I work on a pretty large and complex ASP.Net webforms product, and tests were introduced late into the development cycle of the initial release.  We favored integration testing with real data sources over actual unit tests.  While I did write some tests, I knew that our product was not very testable by design.</p>
<p>Recently we put together a public facing API for programming against the product, that we were able to build from scratch.  This was a natural opening to apply test driven practices and start building unit tests from the get-go.  Due to the service oriented nature of the data that the product consumes, I soon found myself realizing that I needed mocks in a big way.  I gritted my teeth and dove head-first into Rhino.mocks.</p>
<p>Several weeks down the road, it was obvious that Rhino just isn&#039;t right for our environment.  The learning curve is too steep to win quick success with all our developers (and therefore by extension, our project managers).  I began looking for another framework.</p>
<p>This led me on a frustrating research mission to find the differences between frameworks without actually trying them all. Due to a lack of in-depth comparisons of the actual capabilities of the various mocking frameworks, I&#039;ve ended up putting together this chart.  I&#039;m hoping it helps some people.  My interest is very high in this arena, so I will be keeping it up to date.</p>
<p>(Just for interest&#039;s sake -- we ended up choosing Moq, due to the ease of the API.   The philosophy of Moq jives perfectly with our relatively fast-paced and efficient development environment.  We don&#039;t care about purism -- we care about getting it done.)</p>
<div id="attachment_98" class="wp-caption aligncenter" style="width: 650px"></p>
<div class="mceTemp mceIEcenter">
<dl id="attachment_101" class="wp-caption aligncenter" style="width: 650px;">
<dt class="wp-caption-dt"><img class="size-full wp-image-101" title=".Net Mocking Frameworks" src="http://www.phpvs.net/wp-content/uploads/2009/05/comparison.png" alt=".Net Mocking Framework Comparison" width="640" height="488" /><p class="wp-caption-text">.Net Mocking Framework Comparison </p></div>
</dt>
</dl>
</div>
<p style="text-align: center;"><strong>Other Notes</strong></p>
<table border="1" cellspacing="0" cellpadding="0" width="690" align="center">
<tbody>
<tr>
<td width="330" valign="top"><strong>Rhino</strong></p>
<ul class="unIndentedList">
<li> Mature, flexible framework</li>
</ul>
<ul class="unIndentedList">
<li> Built on Castle DynamicProxy</li>
</ul>
<ul class="unIndentedList">
<li> Very large array of &#034;syntaxes&#034; leads to extreme   confusion when writing tests -- documentation mixed for the new 3.5 fluent syntax</li>
</ul>
<ul class="unIndentedList">
<li> Large community of users</li>
</ul>
</td>
<td width="360" valign="top"><strong>Moq</strong></p>
<ul class="unIndentedList">
<li> New(ish) framework also built on Castle</li>
</ul>
<ul class="unIndentedList">
<li> Requires .Net 3.5 due to its lambda heavy   syntax</li>
</ul>
<ul class="unIndentedList">
<li> No distinction between mocks &amp; stubs,   record/playback (joy!!)</li>
</ul>
<ul class="unIndentedList">
<li> Responsive and active developers and community</li>
</ul>
</td>
</tr>
<tr>
<td width="330" valign="top"><strong>NMock2</strong></p>
<ul class="unIndentedList">
<li> Uses &#034;magic strings&#034; for mocking -- makes tests   brittle</li>
</ul>
<ul class="unIndentedList">
<li> Confusing product version #&#039;s -- Nmock2 is   actually a new team that picked up NMock and continued development</li>
</ul>
</td>
<td width="360" valign="top"><strong>TypeMock.Net</strong></p>
<ul class="unIndentedList">
<li> Powerful framework that uses redirection at   the IL level to create mocks</li>
</ul>
<ul class="unIndentedList">
<li> Expensive ($450/license)</li>
</ul>
<ul class="unIndentedList">
<li> TDD Purists argue that the power of it leads   to poorer design</li>
</ul>
</td>
</tr>
</tbody>
</table>
<p>The above observations were gleaned from many web pages, documentation repositories and blog posts, and reflect my limited understanding of each framework.  <em><strong> There may be errors</strong></em>.   If you think I&#039;m wrong, or you can think of other capability aspects that I&#039;ve overlooked, please let me know!</p>
<p><a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fwww.phpvs.net%2f2009%2f04%2f25%2fnet-mocking-frameworks-capability-comparison%2f"><img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.phpvs.net%2f2009%2f04%2f25%2fnet-mocking-frameworks-capability-comparison%2f&amp;bgcolor=FF9933&amp;cbgcolor=D4E1FD" border="0" alt="kick it on DotNetKicks.com" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpvs.net/2009/04/25/net-mocking-frameworks-capability-comparison/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Defend PHP</title>
		<link>http://www.phpvs.net/2009/03/21/defend-php/</link>
		<comments>http://www.phpvs.net/2009/03/21/defend-php/#comments</comments>
		<pubDate>Sun, 22 Mar 2009 04:27:47 +0000</pubDate>
		<dc:creator>morgan</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.phpvs.net/?p=71</guid>
		<description><![CDATA[I ran across a great discussion at StackOverflow today that started with this question:
I made a tongue-in-cheek comment in another question thread calling PHP a terrible language and it got down-voted like crazy. Apparently there are lots of people here who love PHP.
So I&#039;m genuinely curious. What am I missing? Why makes PHP a good [...]]]></description>
			<content:encoded><![CDATA[<p>I ran across <a title="Convince me that PHP isn't horrible" href="http://stackoverflow.com/questions/309300/defend-php-convince-me-it-isnt-horrible" target="_blank">a great discussion at StackOverflow</a> today that started with this question:</p>
<blockquote><p>I made a tongue-in-cheek comment in another question thread calling PHP a terrible language and it got down-voted like crazy. Apparently there are lots of people here who love PHP.</p>
<p>So I&#039;m genuinely curious. What am I missing? Why makes PHP a good language?</p></blockquote>
<p>The article lists a dozen or so &#034;flaws&#034; with the language, and then continues:</p>
<blockquote><p>Worst of all, PHP convinces people that designing web applications is easy. And it does indeed make much of the effort involved much easier. But the fact is, designing a web application that is both secure and efficient is a very difficult task.</p>
<p>By convincing so many to take up programming, PHP has taught an entire subgroup of programmers bad habits and bad design. It&#039;s given them access to capabilities that they lack the understanding to use safely. This has led to PHP&#039;s reputation as being insecure.</p></blockquote>
<p>Are the flaws in PHP really any different from any other language?</p>
<p>I&#039;m a C# programmer, and I have to disagree with what some of what the original poster asserted were flaws with PHP.  Overly broad implicit type conversions?  Too easy to couple presentation with logic?  Heck, those are the reasons it&#039;s so popular in the first place!  Making web programming easy is a flaw?  Wut?</p>
<p>After wrestling with the back and forth in that discussion, I came to a simple conclusion.    This person has fallaciously concluded that PHP is a bad language based on his perception of its compliance with ivory-tower, computer science academia concepts.   Most of his criteria could basically describe Perl, Javascript, VBScript, heck, even VB6, HTML and C.</p>
<p>Of course PHP isn&#039;t a horrible language.  It&#039;s simply a tool, and based on its wild popularity and simple learning curve, only a fool could conclude that it was a bad one.  Even if it breeds more &#034;unsafe programmers&#034; (which I doubt highly), it&#039;s simply not the language&#039;s responsibility to restrict what you can do just because you might do it.</p>
<p>Every programmer should be able to see that.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpvs.net/2009/03/21/defend-php/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>ASP.Net Load Testing and Optimization Toolkit &#8211; So you want to be a hero</title>
		<link>http://www.phpvs.net/2008/08/11/aspnet-load-testing-and-optimization-toolkit-so-you-want-to-be-a-hero/</link>
		<comments>http://www.phpvs.net/2008/08/11/aspnet-load-testing-and-optimization-toolkit-so-you-want-to-be-a-hero/#comments</comments>
		<pubDate>Mon, 11 Aug 2008 20:52:49 +0000</pubDate>
		<dc:creator>morgan</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[ASP.Net]]></category>
		<category><![CDATA[Optimization]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[optimization asp.net load testing performance toolkit]]></category>

		<guid isPermaLink="false">http://www.phpvs.net/?p=56</guid>
		<description><![CDATA[An overview of 9 types of tools every developer needs to know when optimizing ASP.Net applications.]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.phpvs.net/wp-content/uploads/2008/08/Alpha-Dista-Icon-14.png"><img class="size-full wp-image-230 alignleft" style="margin-right: 1em; border: 0pt none;" title="Tools" src="http://www.phpvs.net/wp-content/uploads/2008/08/Alpha-Dista-Icon-14.png" alt="" width="255" height="255" /></a>One of my passions is optimization.  There&#039;s no code related task I like more than making something run better, faster, snappier -- from tweaking UI registry keys to stripping out crap code -- I want results.   Usually if something is noticeably slow on the user&#039;s end, there&#039;s something fundamentally wrong that can be made faster -- a lot faster.</p>
<p>Why do I love optimization?  It&#039;s because it&#039;s the opposite of a thankless job.  Everyone thanks you.  Your sales team thanks you.  Project Managers thank you. Executive management drools over your optimization report -- they can take it straight to the bank.  Product leads take your report and put it into the release notes.  Or a press release.  You&#039;re the hero!  And it&#039;s downright fun.</p>
<p>Long story short, my team was recently assigned optimization targets for our app for increasing user capacity (+30%) and decreasing startup and postback times (-20%).  During the iteration, the rest of the team was sucked away to emergency projects, and I singlehandedly blew so far past the targets I couldn&#039;t even see them anymore.  Final optimizations included 100% increased concurrent user load and a 97% reduction in postback execution time.  Application startup time was decreased by 40%.  Total code changes was 40 lines.  Call it precision strike coding.  Toss in one nicely formatted &#034;before and after&#034; optimization report, and I&#039;d say it&#039;s been a pretty good couple of weeks.</p>
<p>But you need to know what you&#039;re doing, and where to get started.  You can&#039;t simply sit down in front of the code and start randomly caching things or turning every &#039;+&#039; operator into a StringBuilder. (Note: that&#039;s not a good idea anyway).  But if you get familiar with the following tools, you&#039;ll already know where to start.  So without further ado&#8230;</p>
<h2>The ASP.Net Optimizer&#039;s Toolbox</h2>
<p>If you want to optimize, you need to have an arsenal of tools to troubleshoot and profile your app.  You should be familiar with as many of these tools as possible.</p>
<ol>
<li class="olliemph">Code Profiler</li>
<p class="pemph"><strong>Recommended</strong>: <a href="http://www.red-gate.com/products/ants_profiler/index.htm">RedGate Ants (14-day free trial, $295 to purchase)<br />
</a></p>
<p>Pretty much no exceptions here -- you have to have a profiler.  It&#039;s extremely time consuming and ugly to start adding TimeSpan calculations around every block of code in your app.  For the amount of time it would take to track down one slow line of code &#034;manually&#034;, you could have run four profiler sessions and have your top ten &#034;target list&#034; ready to go, made yourself a sandwich and played a game of foosball.  Not only that, but profilers will identify fast blocks of code that are getting executed ridiculous numbers of times, making them slow overall.</p>
<p>Since I&#039;ve used RedGate&#039;s Ants Profiler pretty much exclusively, that&#039;s all I can recommend here, but others exist.  RedGate is great at profiling code, but I find their memory profiling to be pretty lackluster, so if I need to dig into memory I&#039;ll generally fire up Windbg (see further down).</p>
<li class="olliemph">Application Stress Tool</li>
<p class="pemph"><strong>Recommended</strong>: <a href="http://www.neotys.com/">NeoLoad (10 &#034;virtual user&#034; Free Trial but fairly expensive to purchase)</a><br />
<strong>Also good</strong>: <a href="http://www.microsoft.com/technet/archive/itsolutions/intranet/downloads/webstres.mspx?mfr=true">WAST (Free)<br />
</a></p>
<p>You need to be able to load test your application to see how it performs.  When does it crash?  How many users does it support?  How does your memory, disks, network and processors hold up?  Load testing uncovers errors you couldn&#039;t even dream of by looking at your code -- concurrency issues, how your application performs when resources are unavailable, etc.</p>
<p>Load testing tools pose a problem however, because there is a huge gap between free tools and proprietary tools.  Here&#039;s a list of some of the ones I know for Windows/IIS:</p>
<p><strong>TinyGet (Free) </strong>- run some HTTP requests sequentially in a loop.  Part of IIS 6 Resource Toolkit<br />
<strong>WAST (Free)</strong>- an oldie but a goodie -- record basic web browsing and simulate lots of users<br />
<strong>MS ACT -- </strong>(Application Center Test) -- Next generation from WAST, allows for dynamic variables.  It comes with Enterprise Edition level MSDN subscription.  Thanks to mike for pointing it out.<br />
<strong>NeoLoad </strong>- good bang for the buck, all the functionality you&#039;ll need for even complex AJAX applications, but not cheap and has a predatory pricing model shared by higher end software<br />
<strong>Visual Studio Team Edition for Testers</strong> -- you can buy a lot of NeoLoad virtual users for this kind of cash.<br />
<strong>HP LoadRunner</strong> -- you could probably hire a thousand testers, buy them all computers and have them generate load manually for what you&#039;d pay for this kind of software.</p>
<p>The problem is that the free stuff (TinyGet, WAST) is next to useless for testing sessions and AJAX apps, they&#039;re just not built to handle it.  I&#039;ve recently gotten a lot of experience using Neoload and it&#039;s pretty good software with fantastic support behind it -- you can record complex user sessions with many dynamic parameters, multiple viewstates and have multiple recorded sessions make up a &#034;population&#034; of users to test your app under a broad range of conditions.  It also hooks into the perfmon API to give you flexible reporting and graphs.  Unfortunately they charge per &#034;virtual user&#034; you want to have running, and it&#039;s not real cheap.  Small businesses may find it worthwhile depending on the situation.  Freelancers may want to stick with WAST, look at some other options, or roll their own.</p>
<p>The top range stuff is for medium-very large businesses that can shell out the dough, and I don&#039;t have any experience with them.  For the money, they&#039;d better be good!</p>
<li class="olliemph">Performance Monitor</li>
<p class="pemph"><strong>Recommended</strong>: Performance Monitor (perfmon.exe) (Free)<br />
<strong>Also good</strong>: <a href="http://www.neotys.com/">NeoLoad</a></p>
<p>At what point does your app spike the CPU?  How&#039;s that CLR request queue going?  What&#039;s your heap memory look like?  Microsoft&#039;s perfmon API is very rich and if you don&#039;t have a custom app that hooks into it already, simply type &#034;perfmon.exe&#034; at the command prompt and you have everything you need in Microsoft&#039;s simple MMC app.  You can monitor as many machines as necessary all in the same window or log.  Experiment with recording counter log files and replaying them -- this data can be exported and included for that extra-demanding CTO.  If you&#039;re unfamiliar with perfmon, play around with it -- it&#039;s not too hard to figure out even though the interface is a bit dated.</p>
<li class="olliemph">HTTP Recorder</li>
<p class="pemph"><strong>Recommended</strong>: <a href="http://www.fiddler2.com/fiddler2/">Fiddler2 (Free)<br />
</a></p>
<p>Optimizing your AJAX app?  Confused about how chatty your application is being? You need to be able to see exactly what&#039;s going between client and server -- requests, responses, headers, what&#039;s compressed and what isn&#039;t.  Enter Fiddler2 -- this little proxy server sits between IE and any web page and records all the traffic, and reports it for you in an easy to see format.  Tip:  if you&#039;re looking at your pages on your local machine, use http://machinename instead of http://localhost, since IE ignores going through a proxy for localhost addresses.</p>
<p>Fiddler2 is especially useful for ASP.Net apps because it&#039;s not always clear exactly what kind of HTML is being generated by webcontrols.</p>
<li class="olliemph">Interface Manipulation</li>
<p class="pemph"><strong>Recommended</strong>: <a href="https://addons.mozilla.org/en-US/firefox/addon/1843">Firebug (Free)</a><br />
<strong>Also good</strong>: <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=E59C3964-672D-4511-BB3E-2D5E1DB91038&amp;displaylang=en">Developer Toolbar for IE (Free)<br />
</a></p>
<p>Any web developer by now has heard of the Firebug plug-in for Firefox. It lets you manipulate CSS, HTML and javascript on the fly on any webpage you&#039;re viewing, complete with a javascript debugger and DOM explorer.  In fact, I don&#039;t know what we did without it, back in the good &#039;ol Web 1.5.6.18 days.  If you must develop with IE (*shudder*) you can get the Developer Toolbar for IE, which isn&#039;t nearly as good, but does the job in a pinch.</p>
<li class="olliemph">Debugger</li>
<p class="pemph"><strong>Recommended</strong>: <a href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx">Windbg (Free)</a><br />
<strong>Also good</strong>: <a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=28bd5941-c458-46f1-b24d-f60151d875a3&amp;displaylang=en">DebugDiag (Free)<br />
</a></p>
<p>A good debugger/memory dump analyzer is probably the single most powerful tool in your arsenal if you know how to use it.  Windbg will let you take a snapshot of your application as it&#039;s running or when it crashes, and you can quickly narrow down what&#039;s causing crashes, hangs, excessive memory usage, or identify potential optimizations.  You can explore the runtime stacks, native and CLR, see what every thread was doing, and see what&#039;s in every memory address on your heaps.   If you&#039;ve never used Windbg, there are <a href="http://blogs.msdn.com/tess/pages/net-debugging-demos-information-and-setup-instructions.aspx">fantastic lab-style tutorials</a> at <a href="http://blogs.msdn.com/tess/">Tess&#039; blog</a> at MSDN.  These tutorials will also introduce you to perfmon and tinyget.</p>
<li class="olliemph"><a href="http://code.msdn.microsoft.com/codeanalysis/Release/ProjectReleases.aspx?ReleaseId=553">FXCop (Free)<br />
</a></li>
<p>FXCop can be a useful tool but depending on your environment, it might be more trouble than it&#039;s worth.  Simply put, it scans your code looking for bad coding practices and comes up with a report about how sloppy you are.  Unfortunately, some of the default rules may not apply to your development environment, but with a little effort you can certainly weed out the rules you don&#039;t need and make it more useful for your team.</p>
<li class="olliemph">Viewstate Decoder</li>
<p class="pemph"><strong>Recommended</strong>: <a href="http://www.pluralsight.com/community/media/p/51688.aspx">Fritz Onion&#039;s Viewstate Decoder (Free)<br />
</a></p>
<p>At some point most ASP.Net apps undergo a Viewstate optimization.  Let&#039;s face it, Viewstate can be downright disgusting.  If you&#039;re jumping into the middle of an application, it&#039;s helpful to have some guidance on where the hell it&#039;s all coming from.  Just copy and paste it into a Viewstate decoder and you might find a ton of clues.</p>
<li class="olliemph">Text editor</li>
<p class="pemph"><strong>Recommended</strong>: <a href="http://www.ultraedit.com/">Ultraedit (45 day free trial, $49.95 to buy)</a><br />
<strong>Also good</strong>: <a href="http://www.flos-freeware.ch/notepad2.html">Notepad2 (Free)<br />
</a></p>
<p>As every experienced coder knows, sometimes, you just don&#039;t want to look at something in your IDE.  You just want to open a file fast and be done with it.  I&#039;ve used UltraEdit for a long time and it has great features, useful for optimization.  For example, you can copy a recorded request from Fiddler, paste it into Ultraedit, and immediately count how many times your ultra-long image pathname occurs, and immediately know how many bytes you can shave out of your file.  It has quick and easy syntax highlighting for pretty much any programming language, line numbers, and tracks the file and asks to reload it if it detects changes.  It also detects blocks of code or xml for expanding/collapsing, and hundreds of other features.</ol>
<p>Although I didn&#039;t include<a href="http://www.aisto.com/roeder/dotnet/"> Lutz Roeder&#039;s Reflector</a> in the list since I don&#039;t find that I use it that often when I&#039;m debugging, it&#039;s something you should always have for easy reference, especially if you&#039;re dealing with unfamiliar assemblies.</p>
<p>Good luck optimizing!  Remember to spellcheck your optimization report, and don&#039;t forget to put in a one page executive summary of what a hero you are.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpvs.net/2008/08/11/aspnet-load-testing-and-optimization-toolkit-so-you-want-to-be-a-hero/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>ASP.Net Web Forms dying a slow death?</title>
		<link>http://www.phpvs.net/2008/04/25/aspnet-web-forms-dying-a-slow-death/</link>
		<comments>http://www.phpvs.net/2008/04/25/aspnet-web-forms-dying-a-slow-death/#comments</comments>
		<pubDate>Sat, 26 Apr 2008 02:02:11 +0000</pubDate>
		<dc:creator>morgan</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[ASP.Net]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[REST]]></category>
		<category><![CDATA[Silverlight]]></category>

		<guid isPermaLink="false">http://www.phpvs.net/2008/04/25/aspnet-web-forms-dying-a-slow-death/</guid>
		<description><![CDATA[Being a web programmer for the last 10 years, I&#039;ve seen a few different paradigms come and go in the web world.  Looking around today, I can&#039;t help but think that the writings are on the wall for the ASP.Net &#034;webforms&#034; web application model.  When it debuted, it was revolutionary to have a [...]]]></description>
			<content:encoded><![CDATA[<p>Being a web programmer for the last 10 years, I&#039;ve seen a few different paradigms come and go in the web world.  Looking around today, I can&#039;t help but think that the writings are on the wall for the ASP.Net &#034;webforms&#034; web application model.  When it debuted, it was revolutionary to have a fully typed, compiled OO framework that was virtually portable to mobile and desktop.  However, since then, ASP.Net has not done much to improve the initial offerings.  Yes, the 2.0 framework was much more robust, and VS 2005 had lots of IDE help for webmasters, but fundamentally, the same problems that held developers of 1.0 sites back are holding developers of 3.0 sites back -- namely, the ASP.Net page lifecycle.</p>
<p>Viewstate and lifecycle events are still very confusing for new ASP.Net programmers.  There is no easy way for them to immediately &#034;get it&#034; -- they have to spend the time in the trenches, watching their data disappear on post back, or double-bind, and flail around with building and rendering their own web controls.  They have to see the DataGrid spew its html diarrhea and spend hours customizing it.  They have to have that client ask them &#034;what the hell is all this javascript, and why are the pages so big?&#034; and figure out just what the heck all that gibberish on their pages are.</p>
<p>Moving up the experience chain, Viewstate and lifecycle events represent a significant amount of design and front-end time on a web application even for those that have been doing it for a while.  You have to balance your state management with your html optimization, caching, and application maintainability.  Often you have to build your own state-tracking structures or extend existing ones.  You have to carefully consider whether to roll your own custom controls or buy third party interfaces and rely on their javascript and state programming (or maybe their support team!)  And for very simple &#034;read-only&#034; web sites, viewstate just gets in the way.</p>
<p>So in summary, Viewstate and lifecycle are still be a pain in the butt, and still represent hurdles for new programmers.  Years ago, it was worth the annoyances and problems, because you could write strongly typed, object oriented portable code without getting lost in folders and folders of scripted sites.  So why might it be dying?  Well&#8230;</p>
<p>The first item on the agenda is <a href="http://silverlight.net/">Silverlight</a>.  ASP.Net represented significant advantages for writing portable code that was closer to classic desktop programming, as it abstracted out much of the xhtml.  But now I&#039;ve seen web application developers swoon over Silverlight.  If their reaction is any indication, and the amount of momentum that Microsoft is putting into WPF, many shops are going to give up programming their internal or non-public projects in ASP.Net and move to Silverlight instead.   I&#039;m personally still skeptical about Silverlight&#039;s market penetration, as there are many gaps it doesn&#039;t fill for content publishers.  But it&#039;s not a minor consideration.</p>
<p>Second is the new ASP.Net MVC framework.  MVC is an old model that&#039;s rapidly gaining traction in the web world, and with the introduction of the ASP.Net MVC framework, it is hard to see any clear advantage to the older webforms model.  From <a href="http://weblogs.asp.net/scottgu/archive/2007/11/13/asp-net-mvc-framework-part-1.aspx">Scott Guthrie&#039;s Introductory MVC post</a> a couple months ago:</p>
<blockquote><p>To help enforce testability, the MVC framework today does not support postback events directly to server controls within your Views.  Instead, ASP.NET MVC applications generate hyperlink and AJAX callbacks to Controller actions -- and then use Views (and any server controls within them) solely to render output.  This helps ensure that your View logic stays minimal and solely focused on rendering, and that you can easily unit test your Controller classes and verify all Application and Data Logic behavior independent of your Views. </p></blockquote>
<p>And finally, we come to REST, another model that is gaining traction.  True REST and webforms are mutually exclusive since REST involves heavy reliance on mapping resource locators to known states of an application.  This model has lots of advantages for web services and data-based applications, especially in the realms of testing, while ASP.Net Webform applications are often built around one URL for many states, using Viewstate and Session as your state map, which are of course lost between sessions and server restarts.  </p>
<p>So long story short&#8230; I think we&#039;re seeing the beginning of a new paradigm.  In 5 years, will anyone still be developing with true ASP.Net Webforms?  It will be interesting to see!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpvs.net/2008/04/25/aspnet-web-forms-dying-a-slow-death/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Grandmaster Indeed</title>
		<link>http://www.phpvs.net/2008/03/13/grandmaster-indeed/</link>
		<comments>http://www.phpvs.net/2008/03/13/grandmaster-indeed/#comments</comments>
		<pubDate>Fri, 14 Mar 2008 07:53:04 +0000</pubDate>
		<dc:creator>morgan</dc:creator>
				<category><![CDATA[Software Engineering]]></category>

		<guid isPermaLink="false">http://www.phpvs.net/2008/03/13/grandmaster-indeed/</guid>
		<description><![CDATA[Catching up on my reading tonight and I ended up reading this post from end to end.  It&#039;s a fairly interesting article, and takes a very long road to rehash the old adages of &#034;if at first you don&#039;t succeed&#034; and &#034;practice makes perfect&#034; set against a background of nerdly delights and the occasional [...]]]></description>
			<content:encoded><![CDATA[<p>Catching up on my reading tonight and I ended up <a href="http://www.moserware.com/2008/03/what-does-it-take-to-become-grandmaster.html">reading this post from end to end</a>.  It&#039;s a fairly interesting article, and takes a very long road to rehash the old adages of &#034;if at first you don&#039;t succeed&#034; and &#034;practice makes perfect&#034; set against a background of nerdly delights and the occasional introspective advisement.  However, the form and prose of the post is blogging at it&#039;s finest.  Just the perfect number of visual aids, with a plethora of interesting and well-sourced links -- this post is a marvel just from a writing standpoint. A blogging mini-opus.  Kudos.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpvs.net/2008/03/13/grandmaster-indeed/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>10 Tips for Building Selenium Integration Tests</title>
		<link>http://www.phpvs.net/2008/02/25/10-tips-for-building-selenium-integration-tests/</link>
		<comments>http://www.phpvs.net/2008/02/25/10-tips-for-building-selenium-integration-tests/#comments</comments>
		<pubDate>Mon, 25 Feb 2008 18:56:56 +0000</pubDate>
		<dc:creator>morgan</dc:creator>
				<category><![CDATA[AJAX]]></category>
		<category><![CDATA[ASP.Net]]></category>
		<category><![CDATA[Acceptance Testing]]></category>
		<category><![CDATA[Integration Testing]]></category>
		<category><![CDATA[Selenium]]></category>
		<category><![CDATA[Unit Testing]]></category>

		<guid isPermaLink="false">http://www.phpvs.net/2008/02/25/10-tips-for-building-selenium-integration-tests/</guid>
		<description><![CDATA[A list of ten tips, best practices and code snippets to make writing integration and acceptance tests with Selenium much easier, especially for AJAX applications.]]></description>
			<content:encoded><![CDATA[<p>I've been developing an API for our testers to use when writing GUI integration tests and acceptance tests for our main AJAXified web product.  Having chosen <a href="http://selenium-rc.openqa.org/">Selenium Remote Control </a>as our test engine, and writing many tests by hand and with the <a href="http://selenium-ide.openqa.org/">Selenium IDE Firefox Plugin</a>, I've delved deeply into Selenium this past several weeks.  (I've also managed to not only isolate it from our testers, but make our tests portable to any machine that you'd like to use, with no installs or executable paths, but I'll save that magic for another post <img src='http://www.phpvs.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> )</p>
<p>
So from the last few weeks, I thought I'd share some tips I've learned to make writing Selenium tests easier on yourself.
</p>
<ol>
<li> Make a GUI Component map</li>
<p>
              The first thing you should consider is mapping all your GUI elements to strongly typed objects, or at least a dictionary of named XPath strings.  It is much easier on everyone if they can read your code and see something like<br />
<code>Selenium.Click(UIElements["LoginButton"])</code><br />
rather then something like<br />
<code>Selenium.Click("//div[@id='LoginContainer']/table[1]/tbody[1]<br/>/tr[3]/td[2]/a[1]/img[1]")</code>
        </p>
<p>Hand in hand with this tip, I'll remind you to use Best Practices and get your developers to put in an ID for any web page element that will be interacted with <img src='http://www.phpvs.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />   Also, you can check out the <a href="http://wiki.openqa.org/display/SEL/GUI_Map">Selenium extension called GUI_Map</a> if you're looking to extend the Selenium core for your environment.</p>
<li> Fix the timer code!</li>
<p>
The code that the Selenium IDE generates for a timer loop is terrible! It loops from 0 to your timeout number, checking the condition and then sleeping for one second.  This assumes that the loop itself has a negligible execution time, which is untrue in many cases. I've run into situations where for whatever reason, the timer loop runs <strong>very </strong> slowly depending on the XPath you're checking against.  This means your 60 second timeout actually takes wayyyy longer, which is very annoying.  Use this code instead to more reliably measure elapsed time:
</p>
<div class="igBar"><span id="lcsharp-1"><a href="#" onclick="javascript:showPlainTxt('csharp-1'); return false;">&gt;&gt; show as plain text</a></span></div>
<div class="syntax_hilite"><span class="langName">C#:</span>
<div id="csharp-1">
<div>
<ol>
<li>
<div>DateTime start = DateTime.<span style="color: #0000FF;">Now</span>;</div>
</li>
<li>
<div>TimeSpan ts = DateTime.<span style="color: #0000FF;">Now</span>.<span style="color: #0000FF;">Subtract</span><span style="color: #000000;">&#40;</span>start<span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div><span style="color: #FF0000;">bool</span> bFound = <span style="color: #0600FF;">false</span>;</div>
</li>
<li>
<div><span style="color: #0600FF;">do</span></div>
</li>
<li>
<div><span style="color: #000000;">&#123;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; <span style="color: #0600FF;">try</span></div>
</li>
<li>
<div>&nbsp; &nbsp; <span style="color: #000000;">&#123;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>_selenium.<span style="color: #0000FF;">IsElementPresent</span><span style="color: #000000;">&#40;</span>elementName<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#123;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bFound = <span style="color: #0600FF;">true</span>;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF;">break</span>;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; <span style="color: #000000;">&#125;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; <span style="color: #0600FF;">catch</span> <span style="color: #000000;">&#40;</span>Exception<span style="color: #000000;">&#41;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; <span style="color: #000000;">&#123;</span> <span style="color: #000000;">&#125;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; Thread.<span style="color: #0000FF;">Sleep</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;color:#800000;">1000</span><span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>&nbsp; &nbsp; ts = DateTime.<span style="color: #0000FF;">Now</span>.<span style="color: #0000FF;">Subtract</span><span style="color: #000000;">&#40;</span>start<span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div><span style="color: #000000;">&#125;</span></div>
</li>
<li>
<div><span style="color: #0600FF;">while</span> <span style="color: #000000;">&#40;</span>ts.<span style="color: #0000FF;">TotalMilliseconds</span> &lt;_waittime<span style="color: #000000;">&#41;</span> ;</div>
</li>
<li>
<div>&nbsp;</div>
</li>
<li>
<div><span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>!bFound<span style="color: #000000;">&#41;</span> Assert.<span style="color: #0000FF;">Fail</span><span style="color: #000000;">&#40;</span><span style="color: #808080;">"timeout"</span><span style="color: #000000;">&#41;</span>; </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<li>MouseDown() + MouseUp() is better than Click()</li>
<p>
I've found that in many situations a call to <code>Click()</code> won't work, even if the Selenium IDE generated the code.  This is especially true for block elements like table cells that you've styled to be clickable.  Just give up and use a call to <code>MouseDown("element")</code> followed by <code>MouseUp("element")</code>.  This works great in almost every situation.</p>
<li> Simulate Click-Drag with MouseDownAt + MouseUpAt</li>
<p>
I also searched long and hard for a Click-drag method for Selenium until realizing that this can also simply be done with <code>MouseDownAt("elementName", "x1,y1")</code> followed by a <code>MouseUpAt("elementName", "x2,y2")</code>.  Handy if you're testing on-screen drawing or selection tools using click-drags.</p>
<li>Use the Command Pattern</li>
<p>
One of the things the testers appreciate most is that my API handles all the overhead in their tests.  Typically you'll want to split your integration tests into multiple parts, so any given test run would be composed of several tests, each of which runs a sequence of selenium commands.  In order to reset our test environment for each test, I made heavy use of the Command pattern to implement file undo stacks, reversible web-steps, etc.  That way, testers can go deeply into a sequence of commands and simply call the reverse of each command in the stack to back them out to where they started from.  Very useful when testing anything that modifies configurations, test data, etc.</p>
<li>Modal Dialogs are a show-stopper</li>
<p>
There's no getting around this one.  Browser dialogs such as the file download dialog are not testable in Selenium.  There is work being done to allow this in the future, but currently you're out of luck.</p>
<li>Access Javascript Variables in your page with getCurrentWindow()</li>
<p>
If you're using <code>WaitForCondition()</code>, you can use the following snippet to access the DOM for the page that Selenium is running:<br />
<code>selenium.WaitForCondition(<br />"this.browserbot.getCurrentWindow().imgloaded == 1", "15000"<br/>);</code><br />
This is handy for executing existing javascript functions as well as checking variable values.
</p>
<li>Selenium IDE is not your friend: Re-use code to reduce fragility</li>
<p>
A fundamental drawback to using a GUI direct-testing tool is the reliance on locators for GUI elements.  If your locators change, your tests break, even though functionally the app might still be in perfect working order.  As well as using Best Practices to make your tests as robust as possible, you need to centralize your locators (see Tip #1) and build a library of utility functions to re-use.  Having 15 wait-for loops in a test or having the same navigation routines in multiple tests is hideous, not maintainable, and very fragile.
</p>
<li>Use <a href="https://addons.mozilla.org/en-US/firefox/addon/1843">Firebug </a>+ Selenium IDE for XPath finding</li>
<p>
While the Selenium IDE will choose the shortest XPath it can find when it generates your test code, often it isn't what you want.  If you don't want to edit the default behaviours of the IDE tool (which requires some javascript tinkering), I find it helpful to just use the <a href="https://addons.mozilla.org/en-US/firefox/addon/1843">Firebug extension for Firefox</a> and hit F12 to bring up Firebug when the Selenium IDE won't generate a good locator for you.  Use firebug to view the element and determine the XPath you need, replace it in the Selenium IDE, and continue along your merry way.</p>
<li> Use the following code to test for all finished callbacks</li>
<p>
             If you're making use of a framework that is using the <a href="http://msdn2.microsoft.com/en-us/library/ms178208.aspx">ASP.Net 2.0 Callback architecture</a>, this little snippet can save you a bundle.  The key to AJAX testing with Selenium is making use of the various WaitFor...() methods.  For a normal AJAX request, you would just do a regular <code>WaitForCondition </code>or <code>WaitForElementPresent </code>- so what's different about some callbacks?  If you have a Callback chain - i.e., one callback has a result that sets off another callback -<em> you can't use WaitFors to tell when they're done</em>.  A <code>WaitForElementPresent </code>on something that is changed later on in the callback chain will not work, since the element is present and sitting there while the first callbacks are executing.  A <code>WaitForCondition </code>might work, depending on the specific situation, but generally it's not easy to inject a semaphore around some callback object without making the test very fragile, and having to write code for multiple situations in your app.  And of course using <code>Thread.Sleep()</code> slows down your test unnecessarily and isn't reliable.  What we really need is a reliable generic method to check that all Callbacks are complete before we start Asserting that everything worked out.  So use this:</p>
<p>
<code>WaitForCondition("var finished = 1; for (var i = 0; i < selenium.browserbot.getCurrentWindow().__pendingCallbacks.length; i++) { if (selenium.browserbot.getCurrentWindow().__pendingCallbacks[i] != null){ finished = 0; } }; finished == 1", "15000");</code>
</p>
<p>
This is a semaphore around the ASP.Net <code>__pendingCallbacks </code>array that waits for everything to finish up and returns true when all callbacks are complete.  It times out in 15 seconds (you can change the 15000 parameter to any timeout length you'd like).
</p>
</ol>
<p>There it is - 10 tips for happier test writing.  Hope it helps some people out.</p>
<p><a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fwww.phpvs.net%2f2008%2f02%2f25%2f10-tips-for-building-selenium-integration-tests%2f"><img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.phpvs.net%2f2008%2f02%2f25%2f10-tips-for-building-selenium-integration-tests%2f&#038;bgcolor=FF9933&#038;cbgcolor=D4E1FD" border="0" alt="kick it on DotNetKicks.com" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpvs.net/2008/02/25/10-tips-for-building-selenium-integration-tests/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>HTML manipulation with System.Xml.XmlDocument</title>
		<link>http://www.phpvs.net/2008/02/17/html-manipulation-with-systemxmlxmldocument/</link>
		<comments>http://www.phpvs.net/2008/02/17/html-manipulation-with-systemxmlxmldocument/#comments</comments>
		<pubDate>Mon, 18 Feb 2008 06:13:10 +0000</pubDate>
		<dc:creator>morgan</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://www.phpvs.net/2008/02/17/html-manipulation-with-systemxmlxmldocument/</guid>
		<description><![CDATA[HTML Table of Contents Generator Example
Sometimes it's easy to forget that HTML is just one type of XML, and hence you can utilize the System.Xml library for fun and profit with your HTML.  System.Xml is full of powerful tools to manipulate well-formed documents, and you really don't need to know much about XML to [...]]]></description>
			<content:encoded><![CDATA[<h2>HTML Table of Contents Generator Example</h2>
<p>Sometimes it's easy to forget that HTML is just one type of XML, and hence you can utilize the <code>System.Xml</code> library for fun and profit with your HTML.  <code>System.Xml</code> is full of powerful tools to manipulate well-formed documents, and you really don't need to know much about XML to leverage it.  With two simple lines of code you can have a document loaded into a data structure that has powerful manipulation methods that allow you to do complex tasks. Such as generating a table of contents, for example.</p>
<p>Blake phoned me last night very frustrated after having spent a couple hours scouring the 'tubes for some kind of tool that would take his marked-up html document and generate a table of contents from the heading tags in it.  He started asking my advice about a C# program he had downloaded. It included three forms and over 1000 lines of code, and purported to do what he needed.  Except it didn't... it just kept crashing, and couldn't handle certain nestings of tags, etc. etc.  One look at the code made it pretty clear why... some kind of home-brewed tree structure peppered with variables like "treeUp, treeDown, treeRight, itemBegin, itemEnd".... bleeargh.  <code>XmlDocument </code>to the rescue!</p>
<p>In 45 minutes I had a program whipped up into a console app that did exactly what he needed, and it was essentially only 60 lines of code (plus some jazz for error handling/argument passing).   Let's take a look:</p>
<div class="igBar"><span id="lcsharp-5"><a href="#" onclick="javascript:showPlainTxt('csharp-5'); return false;">&gt;&gt; show as plain text</a></span></div>
<div class="syntax_hilite"><span class="langName">C#:</span>
<div id="csharp-5">
<div>
<ol>
<li>
<div><span style="color: #0600FF;">private</span> <span style="color: #0600FF;">void</span> GenerateTOC<span style="color: #000000;">&#40;</span>XmlNodeList nodelist, StringBuilder sb<span style="color: #000000;">&#41;</span></div>
</li>
<li>
<div><span style="color: #000000;">&#123;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; <span style="color: #0600FF;">foreach</span> <span style="color: #000000;">&#40;</span>XmlNode node <span style="color: #0600FF;">in</span> nodelist<span style="color: #000000;">&#41;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; <span style="color: #000000;">&#123;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>Regex.<span style="color: #0000FF;">IsMatch</span><span style="color: #000000;">&#40;</span>node.<span style="color: #0000FF;">Name</span>, <span style="color: #808080;">"h[1-7]"</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#123;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">//We've found an &quot;h&quot; tag.&nbsp; Update our TOC stringbuilder,</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">//and our original XMLDocument to add anchor tags.</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span><span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">isVerbose</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span> Console.<span style="color: #0000FF;">WriteLine</span><span style="color: #000000;">&#40;</span><span style="color: #808080;">"Found "</span> + node.<span style="color: #0000FF;">Name</span><span style="color: #000000;">&#41;</span>; <span style="color: #000000;">&#125;</span></div>
</li>
<li>
<div>&nbsp;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #FF0000;">String</span> tabs = <span style="color: #808080;">""</span>;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #FF0000;">int</span> hLevel = <span style="color: #FF0000;">int</span>.<span style="color: #0000FF;">Parse</span><span style="color: #000000;">&#40;</span>node.<span style="color: #0000FF;">Name</span>.<span style="color: #0000FF;">Substring</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;color:#800000;">1</span>, <span style="color: #FF0000;color:#800000;">1</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>hLevel != <span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">lastHLevel</span><span style="color: #000000;">&#41;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#123;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>hLevel &lt;this.<span style="color: #0000FF;">lastHLevel</span><span style="color: #000000;">&#41;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#123;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">//Retreat to a less indented block level</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> i = <span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">lastHLevel</span> - <span style="color: #FF0000;color:#800000;">1</span>; i&gt; hLevel - <span style="color: #FF0000;color:#800000;">1</span>; i--<span style="color: #000000;">&#41;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#123;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tabs = <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color: #008000;">new</span></a> <span style="color: #FF0000;">String</span><span style="color: #000000;">&#40;</span><span style="color: #808080;">'<span style="color: #008080; font-weight: bold;">\t</span>'</span>, i<span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sb.<span style="color: #0000FF;">Append</span><span style="color: #000000;">&#40;</span>tabs + <span style="color: #808080;">"&lt;/ul&gt;<span style="color: #008080; font-weight: bold;">\n</span>"</span><span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF;">else</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#123;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">//Indent some more - Add the level difference in indents</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> i = <span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">lastHLevel</span>; i &lt;hLevel; i++<span style="color: #000000;">&#41;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#123;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tabs = <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color: #008000;">new</span></a> <span style="color: #FF0000;">String</span><span style="color: #000000;">&#40;</span><span style="color: #808080;">'<span style="color: #008080; font-weight: bold;">\t</span>'</span>, i<span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sb.<span style="color: #0000FF;">Append</span><span style="color: #000000;">&#40;</span>tabs + <span style="color: #808080;">"&lt;/ul&gt;<span style="color: #008080; font-weight: bold;">\n</span>"</span><span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">//Set lastHLevel to the current HLevel</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">lastHLevel</span> = hLevel;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></div>
</li>
<li>
<div>&nbsp;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">//Generate the TOC entry for this node, with a link to it's anchor.</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tabs = <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color: #008000;">new</span></a> <span style="color: #FF0000;">String</span><span style="color: #000000;">&#40;</span><span style="color: #808080;">'<span style="color: #008080; font-weight: bold;">\t</span>'</span>, <span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">lastHLevel</span><span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sb.<span style="color: #0000FF;">Append</span><span style="color: #000000;">&#40;</span>tabs + <span style="color: #808080;">"&lt;li&gt;&lt;a href=<span style="color: #008080; font-weight: bold;">\"</span>#toc"</span> + <span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">tocCount</span> + <span style="color: #808080;">"<span style="color: #008080; font-weight: bold;">\"</span>&gt;"</span> + node.<span style="color: #0000FF;">InnerXml</span> + <span style="color: #808080;">"&lt;/a&gt;&lt;/li&gt;<span style="color: #008080; font-weight: bold;">\n</span>"</span><span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>&nbsp;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">//Add an anchor tag to the node in the original document</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; node.<span style="color: #0000FF;">InnerXml</span> = <span style="color: #808080;">"&lt;a name=<span style="color: #008080; font-weight: bold;">\"</span>toc"</span> + <span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">tocCount</span>.<span style="color: #0000FF;">ToString</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span> + <span style="color: #808080;">"<span style="color: #008080; font-weight: bold;">\"</span>&gt;"</span> + node.<span style="color: #0000FF;">InnerXml</span> + <span style="color: #808080;">"&lt;/a&gt;"</span>;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">tocCount</span>++;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></div>
</li>
<li>
<div>&nbsp;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">//Now recurse over child nodes</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>node.<span style="color: #0000FF;">ChildNodes</span>.<span style="color: #0000FF;">Count</span>&gt; <span style="color: #FF0000;color:#800000;">0</span><span style="color: #000000;">&#41;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GenerateTOC<span style="color: #000000;">&#40;</span>node.<span style="color: #0000FF;">ChildNodes</span>, sb<span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>&nbsp;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #008080; font-style: italic;">//Finish whatever &lt;ul&gt; level we have open if we're the last child of the root.</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>node.<span style="color: #0000FF;">NextSibling</span> == <span style="color: #0600FF;">null</span> &amp;&amp; node.<span style="color: #0000FF;">ParentNode</span>.<span style="color: #0000FF;">ParentNode</span> == <span style="color: #0600FF;">null</span><span style="color: #000000;">&#41;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#123;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> i = <span style="color: #FF0000;color:#800000;">0</span>; i &lt;this.<span style="color: #0000FF;">lastHLevel</span>; i++<span style="color: #000000;">&#41;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#123;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #FF0000;">String</span> tabs = <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color: #008000;">new</span></a> <span style="color: #FF0000;">String</span><span style="color: #000000;">&#40;</span><span style="color: #808080;">'<span style="color: #008080; font-weight: bold;">\t</span>'</span>, <span style="color: #0600FF;">this</span>.<span style="color: #0000FF;">lastHLevel</span> - i - <span style="color: #FF0000;color:#800000;">1</span><span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sb.<span style="color: #0000FF;">Append</span><span style="color: #000000;">&#40;</span>tabs + <span style="color: #808080;">"&lt;/ul&gt;<span style="color: #008080; font-weight: bold;">\n</span>"</span><span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #000000;">&#125;</span></div>
</li>
<li>
<div>&nbsp; &nbsp; <span style="color: #000000;">&#125;</span></div>
</li>
<li>
<div><span style="color: #000000;">&#125;</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p>
So in line 3, we start looping over every node (i.e. html element) in the document.  Line 5 checks to see if the current node is a header tag with a simple Regular Expression.  Lines 11-34 control the indent level of the TOC's html output - we use one &lt;ul&gt; level for each header level.  (So an h5 tag is nested in 5 &lt;ul&gt; tags.)  Line 37-38 adds some html output for the TOC for the current node, namely we create a TOC list item.  Finally, lines 41 and 42 modify the original <code>XmlDocument </code>object by adding an anchor tag to the html of the current node.  Then we recursively call the function again with the current node's children.  The last bit of code polishes off our TOC output at the very end of our recursion. </p>
<p>(At this point, real purists might interject with the fact that 10 lines of code and an XSLT stylesheet could do the same thing; I'd agree, except in practice I find that executing simple loop-driven tasks with XSLT to be quite cumbersome, and I doubt I could do anything with XSLT in 45 minutes.)</p>
<p>So to use the function above, simply harness the raw power of the <code>System.Xml.XmlDocument </code> object, like so:</p>
<div class="igBar"><span id="lcsharp-6"><a href="#" onclick="javascript:showPlainTxt('csharp-6'); return false;">&gt;&gt; show as plain text</a></span></div>
<div class="syntax_hilite"><span class="langName">C#:</span>
<div id="csharp-6">
<div>
<ol>
<li>
<div>XmlDocument htmldoc = <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color: #008000;">new</span></a> XmlDocument<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>htmldoc.<span style="color: #0000FF;">PreserveWhitespace</span> = <span style="color: #0600FF;">true</span>;</div>
</li>
<li>
<div>htmldoc.<span style="color: #0000FF;">Load</span><span style="color: #000000;">&#40;</span><span style="color: #808080;">"myfile.html"</span><span style="color: #000000;">&#41;</span>; </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>Assuming your HTML is well-formed, you can now pass <code>htmldoc.ChildNodes</code> and a <code>StringBuilder </code>into the recursive function above, and your <code>StringBuilder </code>will come back full of HTML table of contents goodness.  Additionally, your <code>XmlDocument </code>variable will have the corresponding anchors added to the header tags.  Just simply output your <code>StringBuilder </code>and <code>XmlDocument </code>to a file, and voila!  Instant HTML table of contents!  (Might look something like below:)</p>
<div class="igBar"><span id="lcsharp-7"><a href="#" onclick="javascript:showPlainTxt('csharp-7'); return false;">&gt;&gt; show as plain text</a></span></div>
<div class="syntax_hilite"><span class="langName">C#:</span>
<div id="csharp-7">
<div>
<ol>
<li>
<div>StringBuilder sb = <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color: #008000;">new</span></a> StringBuilder<span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div><span style="color: #008080; font-style: italic;">//Assume that the root node is not an &lt;h&gt; tag and build our TOC from the children.</span></div>
</li>
<li>
<div>thisApp.<span style="color: #0000FF;">GenerateTOC</span><span style="color: #000000;">&#40;</span>htmldoc.<span style="color: #0000FF;">ChildNodes</span>, sb<span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>&nbsp;</div>
</li>
<li>
<div><span style="color: #008080; font-style: italic;">//Output TOC</span></div>
</li>
<li>
<div>FileStream fs = <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color: #008000;">new</span></a> FileStream<span style="color: #000000;">&#40;</span><span style="color: #808080;">"TOC.html"</span>, FileMode.<span style="color: #0000FF;">Create</span><span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>StreamWriter sw = <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color: #008000;">new</span></a> StreamWriter<span style="color: #000000;">&#40;</span>fs<span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>sw.<span style="color: #0000FF;">Write</span><span style="color: #000000;">&#40;</span>sb.<span style="color: #0000FF;">ToString</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span><span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>sw.<span style="color: #0000FF;">Close</span><span style="color: #000000;">&#40;</span><span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>&nbsp;</div>
</li>
<li>
<div><span style="color: #008080; font-style: italic;">//Output original document with new &lt;a&gt; tags</span></div>
</li>
<li>
<div>XmlWriter xw = <a href="http://www.google.com/search?q=new+msdn.microsoft.com"><span style="color: #008000;">new</span></a> XmlTextWriter<span style="color: #000000;">&#40;</span><span style="color: #808080;">"OriginalWithAnchors.html"</span>, Encoding.<span style="color: #0000FF;">UTF8</span><span style="color: #000000;">&#41;</span>;</div>
</li>
<li>
<div>htmldoc.<span style="color: #0000FF;">WriteTo</span><span style="color: #000000;">&#40;</span>xw<span style="color: #000000;">&#41;</span>; </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>All that in less than 80 lines of code, 45 minutes, and no XSD's, XSLT, or really, any XML at all.  XmlDocument.Load() is simply one of the greatest functions in the .Net framework.  Instant document object with an implicit tree structure.</p>
<p>Download the code here:  <a href='http://www.phpvs.net/wp-content/uploads/2008/02/htmltoc.zip' title='HTML Table of Contents Generator'>HTML Table of Contents Generator</a>.  It includes a binary .exe file in the "bin\Release" directory, so you don't need Visual Studio if you just want to run the above program <img src='http://www.phpvs.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />   Simply call <code>htmltoc.exe infile.html</code>, and you'll have TOC.html and OriginalWithAnchors.html outputted.  TOC.html contains your nicely formatted table of contents, with links to all the anchors in OriginalWithAnchors.html.</p>
<p>
<a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fwww.phpvs.net%2f2008%2f02%2f17%2fhtml-manipulation-with-systemxmlxmldocument%2f"><img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fwww.phpvs.net%2f2008%2f02%2f17%2fhtml-manipulation-with-systemxmlxmldocument%2f&#038;bgcolor=FF9933&#038;cbgcolor=D4E1FD" border="0" alt="kick it on DotNetKicks.com" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpvs.net/2008/02/17/html-manipulation-with-systemxmlxmldocument/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Silverlight &#8211; Oh no, not this again</title>
		<link>http://www.phpvs.net/2008/02/10/silverlight-oh-no-not-this-again/</link>
		<comments>http://www.phpvs.net/2008/02/10/silverlight-oh-no-not-this-again/#comments</comments>
		<pubDate>Mon, 11 Feb 2008 06:52:47 +0000</pubDate>
		<dc:creator>morgan</dc:creator>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[Silverlight]]></category>

		<guid isPermaLink="false">http://www.phpvs.net/2008/02/10/silverlight-oh-no-not-this-again/</guid>
		<description><![CDATA[Excuse me while I ponder for a minute, but I'm continually surprised by the absolute prostration of some of the development community at the feet of Silverlight.  It's filling the .Net blogspace like crazy right now, and many control developers are already shifting focus to it (Telerik and Infragistics, to name two), citing it [...]]]></description>
			<content:encoded><![CDATA[<p>Excuse me while I ponder for a minute, but I'm continually surprised by the absolute prostration of some of the development community at the feet of Silverlight.  It's filling the .Net blogspace like crazy right now, and many control developers are already shifting focus to it (<a href="http://www.telerik.com/products/silverlight/overview.aspx" title="Silverlight in Bulgaria!" target="_blank">Telerik</a> and <a href="http://www.infragistics.com/hot/silverlight.aspx" title="Invest in Silverlight? Invest in some optimization IMO.  This demo is slow!">Infragistics</a>, to name two), citing it as the "next generation" of the web.  My project manager walked out of the Silverlight talk at code camp a couple weekends ago already trying to plan on how to convert all of our web products to it!  Of course, he's programmed desktop apps for the last 15 years, and finds the ASP.Net page lifecycle burdensome, to say the least, so it wasn't <em>too</em> surprising.</p>
<p>Look at <a href="http://www.realsoftwaredevelopment.com/2008/02/the-silverlight.html" title="Silverlight also grants you 72 virgins" target="_blank">this post on "Real World"</a> for crying out loud.  <a href="http://www.pseale.com/blog/SilverlightVersusMagicalFairylandSilverlight.aspx" title="Magical Fairy Land run by the Church of Silverlight" target="_blank">Peter Seale has a rebuttal</a> that does a great job at summing up my thoughts about the article, but one thing that continually fails to be addressed is "why".  Why Silverlight?  Why do we need it?  Do we <em>need</em> to make web apps behave like desktop apps?  Maybe developers do.... but the average web surfer today is a different story. In fact, I'd go so far as to say that Joe Web will likely resist Silverlight <em>unless</em> it can be introduced seamlessly, won't degrade web performance/user experience, and user interfaces are developed properly... unlike when Flash was first introduced.  The average web surfer expects a web page to act like a web page, and you have 4 seconds for it to load if you want to keep them there.  When was the last time you enjoyed hanging out at an all-flash web site?  And maybe last but not least, if a high-profile security exploit were to be associated with Silverlight at this juncture, it might be a lot of trouble for corporate adoption.</p>
<p>So if Silverlight is going to succeed, there is a lot to overcome.  And maybe it's great for app developers, but <a href="http://blog.digitalbackcountry.com/?p=968" title="Shenanigans, indeed" target="_blank">content publishers still have many unanswered questions</a> and it doesn't look like there are many answers right now.  Not to mention, the demo applications that I've seen have run like turds on any machine older than 3 months, and the 1.1 Alpha release (1.1 alpha??) has drawn a lot of developer ire.</p>
<p>Don't get me wrong - I heartily approve the concept. The point is, Silverlight needs to satisfy a lot more than just application developers. RIA's make up a small portion of the internet. The real web runs on content, from the Library of Congress down to your dog's Facebook application. And every time I hear Silverlight, a little voice in my head whispers "<font size="4">ActiveX</font> <font size="2">ActiveX </font><font size="1">ActiveX</font>"...  I guess I'm still getting over that nuclear disaster.   This reaction to Silverlight just reeks of the reaction to Longhorn during the first couple years of feature marketing (WinFS!), and we all know what happened to Vista.   I'm going to sit on the skeptic fence for a little while longer.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpvs.net/2008/02/10/silverlight-oh-no-not-this-again/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
