<?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>weirdlover</title>
	<atom:link href="http://www.weirdlover.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.weirdlover.com</link>
	<description>I make love to asp.net mvc, c#, vb, legos, ladies, etc.</description>
	<lastBuildDate>Wed, 30 Nov 2011 00:21:35 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Maragogype Chirpy: v2, Attack of the Elderly One-Legged Coffee-Bird</title>
		<link>http://www.weirdlover.com/2011/03/03/chirpy-v2/</link>
		<comments>http://www.weirdlover.com/2011/03/03/chirpy-v2/#comments</comments>
		<pubDate>Thu, 03 Mar 2011 00:18:30 +0000</pubDate>
		<dc:creator>Evan</dc:creator>
				<category><![CDATA[ASP.NET MVC]]></category>
		<category><![CDATA[Visual Studio]]></category>

		<guid isPermaLink="false">http://www.weirdlover.com/?p=516</guid>
		<description><![CDATA[After many months of cave-dwelling and self-imposed anti-societal isolation, I return from the depths of my solitude to humbly (yet proudly) announce the release of <b>Chirpy v2.0</b>! ]]></description>
			<content:encoded><![CDATA[<p>After many months of cave-dwelling and self-imposed anti-societal isolation, I return from the depths of my solitude to humbly (yet proudly) announce the release of <b>Chirpy v2.0</b>! </p>
<p>Now, before I get too carried away here, let me re-divulge the following preface: if youâ€™re completely new to the madness of Chirpy, I recommend that you read about <a href="http://www.weirdlover.com/2010/07/18/chirpy-attains-godlike-abilities-in-version-1-0-0-4/">Chirpyâ€™s core features</a>, which were solidifed and released in Chirpy 1.0.0.4. Then, check out the additional features that we added in <a href="http://www.weirdlover.com/2010/09/07/chirpy-to-the-xxxtreme-v1-0-0-5-da-kine-release/">Chirpy 1.0.0.5</a>. If you&#8217;re still not quite convinced that Chirpy will help reinvigorate all of your decompressed hopes and dreams, listen to the almighty David Ebbo <a href="http://blogs.msdn.com/b/davidebb/archive/2010/07/17/check-out-chirpy-a-very-cool-add-in-to-run-t4mvc-and-do-many-other-cool-things.aspx">wax ornithological</a> about the goodness of the Chirpy Bird. Then, once you&#8217;re up to speed, come on back to this almighty post.</p>
<hr />
<p>Like last time, Iâ€™d like begin by tipping my hat to the main Chirpy contributors. Please send them money, Cadbury Eggs, hugs, fresh tulips, etc.:  Francis Noel (aka <a href="http://twitter.com/#!/ploufs">ploufs</a>), <a href="http://andy.edinborough.org/">Andy Edinborough</a>, <a href="http://blog.waynebrantley.com/">Wayne Brantley</a>, and newcomers <a href="http://mpdreamz.nl/">Martijn Laarman</a>, and <a href="http://twitter.com/#!/domenicdenicola">Domenic Denicola</a>. I owe them all a huge thank you. They&#8217;ve kept this project alive (and uber vibrant) while I was away trying to keep my job and my love life (brown chicken, brown cow) alive, so I can&#8217;t thank them enough. If you happen to feel the same affinity for their amazing craftsmanship, please consider <a href="http://www.pledgie.com/campaigns/12969">donating a couple bucks to the team</a>. If you donate enough wads of cash-money-cash-cash, we&#8217;ll release a future version of Chirpy in your honor (eh, Budweiser Chirpy, anyone?).</p>
<p>If you&#8217;re teary-eyed or vulnerable to digital persuasion, you can donate to us here:</p>
<p><a href="http://www.pledgie.com/campaigns/12969"><img src="http://www.pledgie.com/campaigns/12969.png" alt="12969 Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird"  title="Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird" /></a></p>
<p>Bored already? Ignore me, and <b><a href="http://chirpy.codeplex.com">Download Chirpy now</a></b>.</p>
<hr />
<p>Okay, then. Welcome back. Let&#8217;s get down to it. In <b>version 2</b> of Chirpy, we&#8217;ve fixed a lot of the bugs that were troubling our fellow Chirpsters. We&#8217;ve also added a slew of new mantastic features. We hope you like them:</p>
<ul>
<li><a href="#coffeescript">CoffeeScript Support</a></li>
<li><a href="#off-closure">Offline Google Closure Support</a></li>
<li><a href="#uglify">Uglify.js Support</a></li>
<li><a href="#jshint">JSHint Support</a></li>
<li><a href="#razor">Inline minification for Razor Views</a></li>
<li><a href="#console">The Consolation Prize (Chirpy Console)</a></li>
</ul>
<hr />
<h4 id="coffeescript">Feature 1: CoffeeScript Support</h4>
<p><strong>Step 1:</strong> Read up on CoffeeScript. You can find out all you need to know on the <a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a> homepage. Make sure to check out the thorough <a href="http://jashkenas.github.com/coffee-script/documentation/docs/grammar.html">documentation</a>, if you&#8217;re into that kind of stuff.</p>
<p><strong>Step 2:</strong> Add a <strong>.chirpy.coffee</strong> file to your project. </p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2011/03/coffee_file.png"><img src="http://www.weirdlover.com/wp-content/uploads/2011/03/coffee_file-e1299097336103.png" alt="coffee file e1299097336103 Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird" title="coffee_file" width="700" height="380" class="alignnone size-full wp-image-521" /></a></p>
<p><strong>Step 3:</strong> Add some CoffeeScript into your CoffeeScript file.</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2011/03/coffee_sample.png"><img src="http://www.weirdlover.com/wp-content/uploads/2011/03/coffee_sample-e1299097474373.png" alt="coffee sample e1299097474373 Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird" title="coffee_sample" width="700" height="380" class="alignnone size-full wp-image-522" /></a></p>
<p><strong>Step 4:</strong> When you save your file, you&#8217;ll notice that Chirpy creates <strong>.js</strong> and <strong>.min.js</strong> codebehind files. Open those files to see the JavaScript generated from your CoffeeScript. Time to bask in the caffeinated glory:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2011/03/coffee_output.png"><img src="http://www.weirdlover.com/wp-content/uploads/2011/03/coffee_output-e1299097813630.png" alt="coffee output e1299097813630 Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird" title="coffee_output" width="700" height="380" class="alignnone size-full wp-image-523" /></a></p>
<hr />
<h4 id="off-closure">Feature 2: Offline Google Closure Support</h4>
<p><strong>Step 1:</strong>  Download JRE (Java Runtime Environment) from java.com. You can snag it by clicking <a href="http://www.java.com/en/download/chrome.jsp?locale=en&#038;host=www.java.com">here</a>.</p>
<p><strong>Step 2:</strong> Install JRE. This can take some time. Consider watching an episode of Law &#038; Order. If you can&#8217;t find an episode of Law &#038; Order on TV, you&#8217;re probably not trying hard enough. If JRE is still installing, eat dinner. Learn your kids&#8217; names. Hug them. Take a nap.</p>
<p><strong>Step 3:</strong> Open Visual Studio. Click <strong>Tools > Options > Chirpy > Google Closure Compiler</strong>. </p>
<p><strong>Step 4:</strong> Select the option to <strong>Use Offline Google Closure Compiler</strong>. If you&#8217;re lucky, Chirpy will automatically find JRE. If you&#8217;re not lucky, you&#8217;ll have to manually direct Chirpy to the honeypot.  </p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2011/03/gct_offline.png"><img src="http://www.weirdlover.com/wp-content/uploads/2011/03/gct_offline-e1299098880495.png" alt="gct offline e1299098880495 Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird" title="gct_offline" width="700" height="379" class="alignnone size-full wp-image-524" /></a></p>
<p><strong>Step 5:</strong> Download <strong>compiler.jar</strong>. You can download it <a href="http://weirdlover.com/chirpy/compiler.zip">here</a>.</p>
<p><strong>Step 6:</strong> Unzip <strong>compiler.jar</strong> and place the file in your <strong>Visual Studio AddIns</strong> folder.</p>
<p><strong>Step 7:</strong> You&#8217;re good to go! When you use gct, your files will be minified locally:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2011/03/gct_offline1.png"><img src="http://www.weirdlover.com/wp-content/uploads/2011/03/gct_offline1-e1299103533490.png" alt="gct offline1 e1299103533490 Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird" title="gct_offline" width="700" height="378" class="alignnone size-full wp-image-525" /></a></p>
<hr />
<h4 id="uglify">Feature 3: Uglify.js Support</h4>
<p><strong>Step 1:</strong> Learn about Uglify.js <a href="https://github.com/mishoo/UglifyJS">here</a>. If you think it&#8217;s the uglifier for you, jump to step 2.</p>
<p><strong>Step 2:</strong> Create an <strong>.uglify.js</strong> file. Save it. And, mung-balls:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2011/03/uglify-unmin.png"><img src="http://www.weirdlover.com/wp-content/uploads/2011/03/uglify-unmin-e1299103841282.png" alt="uglify unmin e1299103841282 Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird" title="uglify unmin" width="700" height="380" class="alignnone size-full wp-image-526" /></a></p>
<p>Your <a href="http://www.weirdlover.com/birds/never.html">uglified</a> output is generated. (Insert joke about your boyfriend/girlfriend/husband/wife/fakefriend here):</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2011/03/uglify-min.png"><img src="http://www.weirdlover.com/wp-content/uploads/2011/03/uglify-min-e1299103877794.png" alt="uglify min e1299103877794 Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird" title="uglify min" width="700" height="379" class="alignnone size-full wp-image-527" /></a></p>
<hr />
<h4 id="jshint">Feature 4: JSHint Support</h4>
<p><strong>Step 1:</strong> Learn about JSHint <a href="http://jshint.com/">here</a>. Snag the source code from <a href="https://github.com/jshint/jshint/">here</a>. Learn about the JSHint quality rules <a href="http://jshint.com/#docs">here</a>. If you&#8217;re super-bored, check out Crockford&#8217;s <a href="http://jslint.com/">JSLint</a> from which JSHint is humbly derived.</p>
<p><strong>Step 2:</strong> Do something stupid in your chirpy-managed JavaScript file. Like, eh, use the evil <strong>eval()</strong>. Save your file, and watch JSHint get ornery:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2011/03/jshint.png"><img src="http://www.weirdlover.com/wp-content/uploads/2011/03/jshint-e1299104002686.png" alt="jshint e1299104002686 Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird" title="jshint" width="700" height="379" class="alignnone size-full wp-image-528" /></a></p>
<p><strong>Step 3:</strong> If you prefer to be left alone, you can turn JSHint off. To do so, go to <strong>Tools > Options > Chirpy > JavaScript</strong>, and unselect <strong>Run JSHint</strong>.</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2011/03/jshint_off.png"><img src="http://www.weirdlover.com/wp-content/uploads/2011/03/jshint_off-e1299104112735.png" alt="jshint off e1299104112735 Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird" title="jshint_off" width="700" height="379" class="alignnone size-full wp-image-529" /></a></p>
<hr />
<h4 id="razor">Feature 5: Inline minification for Razor Views</h4>
<p><strong>Step 1:</strong> In your MVC project, create a new Razor View. Name the view Test.chirp.cshtml.</p>
<p><strong>Step 2:</strong> Add some javascript, css, or DotLess to your file:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2011/03/razor.png"><img src="http://www.weirdlover.com/wp-content/uploads/2011/03/razor-e1299107496520.png" alt="razor e1299107496520 Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird" title="razor" width="700" height="380" class="alignnone size-full wp-image-530" /></a></p>
<hr />
<h4 id="console">The Consolation Prize (Chirpy Console)</h4>
<p>So, if the visual bling of VS2010 doesn&#8217;t strike your fancy, you can now run chirpy from the command line. Keep in mind, though: the console version of Chirpy is still in its early stages infancy, so if you have any ideas/concerns/insights, please fling them my way. Until then, the Chirpy Console shall serve as simple consolation prize (sorry) for the command-line pervs out there.  </p>
<p><strong>Step 1:</strong> Download the Console Chirpy zip file, <a href="http://www.weirdlover.com/chirpy/ChirpyConsole.zip">here</a>.</p>
<p><strong>Step 2:</strong> Unzip the file and place the folder somewhere warm and safe.</p>
<p><strong>Step 3:</strong> Pick a directory that you want Chirpy to chew through. For this example, I went with this doozy of a folder:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2011/03/console_chew1.png"><img src="http://www.weirdlover.com/wp-content/uploads/2011/03/console_chew1-e1299109880346.png" alt="console chew1 e1299109880346 Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird" title="console_chew" width="700" height="312" class="alignnone size-full wp-image-533" /></a></p>
<p><strong>Step 4:</strong> Feed Chirpy the directory.</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2011/03/console_chewed.png"><img src="http://www.weirdlover.com/wp-content/uploads/2011/03/console_chewed.png" alt="console chewed Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird" title="console_chewed" width="683" height="399" class="alignnone size-full wp-image-532" /></a></p>
<p><strong>Step 5:</strong> Bask in the darkness. Check out the folder that you chewed through. Your minified files have been created/updated:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2011/03/console_spit.png"><img src="http://www.weirdlover.com/wp-content/uploads/2011/03/console_spit-e1299109968661.png" alt="console spit e1299109968661 Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird" title="console_spit" width="700" height="315" class="alignnone size-full wp-image-534" /></a></p>
<hr/>
<p>Ready? Run over to Codeplex when you&#8217;re ready and <b><a href="http://chirpy.codeplex.com/">download Chirpy</a></b>.</p>
<p>That&#8217;s it! Once again, Chirpy says (as always): <strong>Happy Coding!</strong> </p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/05/Zippy.jpg"><img src="http://www.weirdlover.com/wp-content/uploads/2010/05/Zippy.jpg" alt="Zippy Maragogype Chirpy: v2, Attack of the Elderly One Legged Coffee Bird" title="Zippy" width="355" height="451" class="aligncenter size-full wp-image-64" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.weirdlover.com/2011/03/03/chirpy-v2/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Chirpy to the XXXtreme &#8211; v1.0.0.5 Release (Party? NSFW? Eh? Eh?)</title>
		<link>http://www.weirdlover.com/2010/09/07/chirpy-to-the-xxxtreme-v1-0-0-5-da-kine-release/</link>
		<comments>http://www.weirdlover.com/2010/09/07/chirpy-to-the-xxxtreme-v1-0-0-5-da-kine-release/#comments</comments>
		<pubDate>Tue, 07 Sep 2010 01:36:59 +0000</pubDate>
		<dc:creator>Evan</dc:creator>
				<category><![CDATA[Visual Studio]]></category>
		<category><![CDATA[.Less]]></category>
		<category><![CDATA[Chirpy]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Masher]]></category>
		<category><![CDATA[Minifier]]></category>

		<guid isPermaLink="false">http://www.weirdlover.com/?p=503</guid>
		<description><![CDATA[I'm excited to announce the release of Chirpy v.1.0.0.5--Chirpy to the XXXtreme. That's right. This version of Chirpy will blow the pants off of every clothed person in the universe. So, if you haven't gotten dressed already, don't bother... Before diving too deep into the realm of the extreme, let me re-divulge the following preface: if you're <em>completely</em> new to the madness of Chirpy, I recommend that read about <a href="http://www.weirdlover.com/2010/07/18/chirpy-attains-godlike-abilities-in-version-1-0-0-4/">Chirpy's core features</a>. ]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m excited to announce the release of Chirpy v.1.0.0.5&#8211;Chirpy to the XXXtreme. That&#8217;s right. This version of Chirpy will blow the pants off of every clothed person in the universe. So, if you haven&#8217;t gotten dressed already, don&#8217;t bother.</p>
<p>Before diving too deep into the realm of the extreme, let me re-divulge the following preface: if you&#8217;re <em>completely</em> new to the madness of Chirpy, I recommend that you read about <a href="http://www.weirdlover.com/2010/07/18/chirpy-attains-godlike-abilities-in-version-1-0-0-4/">Chirpy&#8217;s core features</a>. You can also watch David Ebbo <a href="http://mvcconf.tekpub.com/">demo Chirpy</a> as a part of his MvcConf presentation. That should get you caught up. And once you&#8217;re caught up, come on back to this post.</p>
<p>Another important side-note: Chirpy&#8217;s current warp-like maturation is largely due to the superb and continued contributions of <a href="http://andy.edinborough.org/">Andy Edinborough</a> and <a href="http://www.twitter.com/ploufs">Francis Noel</a>. As a thanks for their support, and as an impetus for continued feather-laden progress, I kindly ask that you consider throwing a dollar or two (hundred [thousand]) into our <a href="http://pledgie.com/campaigns/12969">donation hat</a>. Andy, after all, has four children, and each requires at least one plate of sustenance per day. And I, although completely childless, have an insatiable, child-like desire for candy bars and diet Red Bulls. </p>
<p>At the very least, if you have experienced the pleasure of the flightless Chirpy bird (or if you feel like complaining about how crappy Chirpy is), go to Chirpy&#8217;s <a href="http://chirpy.codeplex.com/">Codeplex page</a> and write a comment or two. Or, if you&#8217;d like to follow the project more closely, feel free to follow all of Chirpy&#8217;s developers on <a href="http://twitter.com/#/list/evannagle/chirpsters">Twitter</a>. </p>
<p>Alright. Without further ado:</p>
<hr/>
<h2>Xxxtreme New Chirpy Features</h2>
<p>Let&#8217;s start with the obvious: you can download <strong>Chirpy v1.0.0.5</strong> <a href="http://chirpy.codeplex.com/releases/view/51519">here</a>.</p>
<p>Got it? Good.</p>
<p>Now, here&#8217;s an overview of all of the new features that you&#8217;ve just blessed yourself with. Click on the feature below that most likely suits your fancy, or, if you&#8217;re a real sucker for e-pain, you can scroll through the whole document (may God help you) until you reach the very, very end.</p>
<ul>
<li><a href="#first">Chirpy Handles Seven New File Extensions</a></li>
<li><a href="#second">Chirpy Handles Inline Aspx and Ascx Translation and Minification</a></li>
<li><a href="#third">Chirpyâ€™s Source is Now More Modularized and Multi-Threaded</a></li>
<li><a href="#fourth">Chirpy Can Use Google Closure Tools Offline</a></li>
<li><a href="#fifth">Chirpyâ€™s Config Files Now Tote Intellisense</a></li>
</ul>
<hr/>
<div id="first">
<h4>Feature 1: Chirpy Handles Seven New File Extensions</h4>
<p>The new extensions include:</p>
<blockquote>
<ol>
<li><strong>.michaelash.css</strong>. Minify your stylesheets using Michael Ash&#8217;s Regex enhancements. If you&#8217;re unfamiliar with Michael Ash&#8217;s Regex CSS enhancements, you can read more about the project <a href="http://regexadvice.com/blogs/mash/archive/2008/03/27/Additional-CSS-minifying-regex-patterns.aspx">here</a>.</li>
<li><strong>.hybrid.css</strong>. Minify your stylesheets with YUI Compressor + Michael Ash&#8217;s Regex enhancements.</li>
<li><strong>.msajax.css</strong>.  Minify your stylesheets with Ms Ajax Minifier. If you&#8217;re unfamiliar with Microsoft&#8217;s Ajax Minifier, you can read more about the library <a href="http://aspnet.codeplex.com/releases/view/40584">here</a>.</li>
<li><strong>.msajax.js</strong>.  Minify your javascript files with Ms Ajax Minifier. If you&#8217;re unfamiliar with Microsoft&#8217;s Ajax Minifier, you can read more about the library <a href="http://aspnet.codeplex.com/releases/view/40584">here</a>.</li>
<li><strong>.michaelash.less</strong>. Translate your Less files with the DotLess Translator, and minify the outputted CSS file with Michael Ash&#8217;s Regex enhancements.</li>
<li><strong>.hybrid.less</strong>. Translate your Less files with the DotLess Translator, and minify the outputted CSS file with YUI Compressor + Michael Ash&#8217;s Regex enhancements.</li>
<li><strong>.msajax.less</strong>.  Translate your Less files with the DotLess Translator, and minify the outputted CSS file with MS Ajax Minifier.</li>
</ol>
</blockquote>
</div>
<div id="second">
<hr/>
<h4>Feature 2: Chirpy Handles Inline Aspx and Ascx Translation and Minification</h4>
<p><strong>Step 1:</strong> In your MVC or WebForms project, create a new <strong>View</strong>. Name the view <strong>Test.chirp.aspx</strong>:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/09/TestAspx.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/09/TestAspx-e1283818818923.png" alt="TestAspx e1283818818923 Chirpy to the XXXtreme   v1.0.0.5 Release (Party? NSFW? Eh? Eh?)" title="TestAspx" width="700" height="415" class="alignnone size-full wp-image-510" /></a></p>
<p><strong>Step 2:</strong> Insert a new inline script into your <strong>Test.chirp.aspx</strong> file:</p>
<pre>
<code class="html">
&lt;asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    &lt;h2>Test.Chirp.aspx&lt;/h2>

    &lt;script type="text/javascript">
        function thisWillGetMinifiedYo() {
            alert("hi");
            alert("bye");
        }
    &lt;/script>
&lt;/asp:Content>
</code>
</pre>
<p><strong>Step 3:</strong> In the codebehind <strong>Test.aspx</strong> file, you&#8217;ll notice that all of your inline javascript has been minified:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/09/TestAspxBehind-e1283819056728.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/09/TestAspxBehind-e1283819056728.png" alt="TestAspxBehind e1283819056728 Chirpy to the XXXtreme   v1.0.0.5 Release (Party? NSFW? Eh? Eh?)" title="TestAspxBehind" width="700" height="416" class="alignnone size-full wp-image-511" /></a></p>
<p><strong>Step 4:</strong> Now, for the fun part. Let&#8217;s create an inline Less tag. And let&#8217;s add some less code into our aspx page:</p>
<pre>
<code class="html">
&lt;asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" runat="server">
    &lt;style type="text/less">
        @color : #123456;

        tag
        {
            background-color:@color;
        }
    &lt;/style>
&lt;/asp:Content>
</code>
</pre>
<p><strong>Step 5:</strong> In the codebehind <strong>Test.aspx</strong> file, you&#8217;ll notice that your inline Less code has been translated into minified CSS. Fun for all (don&#8217;t mind the mistake here, if you can sniff it out):</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/09/TestLessBehind.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/09/TestLessBehind-e1283819486752.png" alt="TestLessBehind e1283819486752 Chirpy to the XXXtreme   v1.0.0.5 Release (Party? NSFW? Eh? Eh?)" title="TestLessBehind" width="700" height="417" class="alignnone size-full wp-image-512" /></a>
</div>
<div id="third">
<hr/>
<h4>Feature 3: Chirpy&#8217;s Source is Now More Modularized and Multi-Threaded</h4>
<p>It&#8217;s easier than ever to add your own translator to Chirpy. For starters, if you haven&#8217;t already, download and open Chirpy&#8217;s source project (you can download the source at <a href="http://chirpy.codeplex.com/SourceControl/list/changesets">Codeplex</a>). Easy enough. Now, for <strong>Step 1</strong>, go ahead and open up the project in Visual Studio:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/09/ChirpProj1.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/09/ChirpProj1-e1283816664518.png" alt="ChirpProj1 e1283816664518 Chirpy to the XXXtreme   v1.0.0.5 Release (Party? NSFW? Eh? Eh?)" title="ChirpProj" width="700" height="416" class="alignnone size-full wp-image-506" /></a></p>
<p><strong>Step 2</strong>: Create a new <strong>Engine</strong> class in the <strong>Engines</strong> folder. In this example, I&#8217;ll create a really simple (read: stupid) Transform Engine:</p>
<pre>
<code class="csharp">
using System;

namespace Zippy.Chirp.Engines
{
    public class TestEngine : TransformEngine
    {
        public TestEngine()
        {
            Extensions = new string[] { ".test.moo", ".test.foo" }; //extensions that this engine handles
            OutputExtension = ".test"; //outputted extension
        }

        public override string Transform(string fullFileName, string text, EnvDTE.ProjectItem projectItem)
        {
            return "//here is the outputted text:" + Environment.NewLine + text;
        }

        public override void Process(Manager.VSProjectItemManager manager, string fullFileName, EnvDTE.ProjectItem projectItem, string baseFileName, string outputText)
        {
            //process occurs after transformation
            //you can override, if you so choose...
            base.Process(manager, fullFileName, projectItem, baseFileName, outputText);
        }
    }
}
</code>
</pre>
<p><strong>Step 3</strong>: Once your Engine class is built, you need to register your new engine in the <strong>Chirp</strong> class (Chirp.cs):</p>
<pre>
<code class="csharp">
internal TestEngine TestEngine { get; set; }

public void LoadActions() {
    if(_EngineManager == null || _EngineManager.IsDisposed)
        _EngineManager = new EngineManager(this);

    _EngineManager.Clear();
    _EngineManager.Add(YuiCssEngine = new YuiCssEngine());
    _EngineManager.Add(YuiJsEngine = new YuiJsEngine());
    _EngineManager.Add(ClosureCompilerEngine = new ClosureCompilerEngine());
    _EngineManager.Add(LessEngine = new LessEngine());
    _EngineManager.Add(MsJsEngine = new MsJsEngine());
    _EngineManager.Add(MsCssEngine = new MsCssEngine());
    _EngineManager.Add(ConfigEngine = new ConfigEngine());
    _EngineManager.Add(ViewEngine = new ViewEngine());
    _EngineManager.Add(T4Engine = new T4Engine());
    _EngineManager.Add(TestEngine = new TestEngine()); //here's our baby
}
</code>
</pre>
<p><strong>Step 4:</strong> Rebuild the vsi package. If you&#8217;re not comfortable creating a vsi file manually (as described <a href="http://msdn.microsoft.com/en-us/library/ms246580%28VS.80%29.aspx">here</a>), you can automatically generate the vsi file as part of the Build process. Just make sure that the following commands are included in the <strong>Post-build event command line</strong>:</p>
<blockquote><p>
del &#8220;$(ProjectDir)$(OutDir)Chirpy.vsi&#8221;<br />
&#8220;$(ProjectDir)$(OutDir)\ILMerge&#8221; /out:&#8221;$(ProjectDir)$(OutDir)Chirpy.dll&#8221; &#8220;$(TargetPath)&#8221; &#8220;$(ProjectDir)$(OutDir)EcmaScript.NET.modified.dll&#8221; &#8220;$(ProjectDir)$(OutDir)Yahoo.YUI.Compressor.dll&#8221; &#8220;$(ProjectDir)$(OutDir)dotless.Core.dll&#8221; &#8220;$(ProjectDir)$(OutDir)AjaxMin.dll&#8221;<br />
&#8220;$(ProjectDir)$(OutDir)7za.exe&#8221; u Chirpy.zip &#8220;$(ProjectDir)$(OutDir)Chirpy.dll&#8221; &#8220;$(ProjectDir)$(OutDir)Chirpy.vscontent&#8221; &#8220;$(ProjectDir)$(OutDir)Zippy.AddIn&#8221;<br />
rename &#8220;$(ProjectDir)$(OutDir)Chirpy.zip&#8221; &#8220;Chirpy.vsi&#8221;
</p></blockquote>
<p><strong>Step 5:</strong> Open the vsi file, and install your customized version of Chirpy!</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/09/ChirpyVSI.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/09/ChirpyVSI-e1283817085945.png" alt="ChirpyVSI e1283817085945 Chirpy to the XXXtreme   v1.0.0.5 Release (Party? NSFW? Eh? Eh?)" title="ChirpyVSI" width="700" height="416" class="alignnone size-full wp-image-507" /></a></p>
<p><strong>Step 6:</strong> Test out your awesome new engine. For my TestEngine, I created a file with the extension &#8220;.test.moo&#8221;. As a result, Chirpy creates a codebehind file:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/09/TestMoo.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/09/TestMoo-e1283817558218.png" alt="TestMoo e1283817558218 Chirpy to the XXXtreme   v1.0.0.5 Release (Party? NSFW? Eh? Eh?)" title="TestMoo" width="700" height="418" class="alignnone size-full wp-image-508" /></a></p>
<p><strong>Step 7:</strong> Take a look at the codebehind file that Chirpy created. Notice that we &#8220;transformed&#8221; the .test.moo file by adding a comment at the top of the file:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/09/MyTest.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/09/MyTest-e1283817377855.png" alt="MyTest e1283817377855 Chirpy to the XXXtreme   v1.0.0.5 Release (Party? NSFW? Eh? Eh?)" title="MyTest" width="700" height="415" class="alignnone size-full wp-image-509" /></a></p>
<p><strong>Step 8:</strong> If your engine might be helpful to other developers, please (and I mean <em>PLEASE</em>) consider submitting your addition to the project. I&#8217;d be excited to include it. And I&#8217;d be forever grateful for your contribution.
</div>
<div id="fourth">
<hr/>
<h4>Feature 4: Use Google Closure Tools Offline</h4>
<p>Though this feature has yet to be integrated into the main Chirpy project, <a href="http://erikzaadi.com/">Erik Zaadi</a> has been working on a <em>great</em> Chirpy extension. The extension allows for offline use of Google Closure Tools. If you&#8217;re interested in using Erik&#8217;s madness, you can read about it <a href="http://erikzaadi.com/blog/2010/08/01/StartupWeekendAndroidVimRazorAndABitOfChirpy.xhtml">here</a>, and you can download the fork at <a href="http://chirpy.codeplex.com/SourceControl/network/Forks/erikzaadi/GoogleClosureEnhancements">Codeplex</a>.
</div>
<div id="fifth">
<hr/>
<h4>Feature 5: Chirpy&#8217;s Config File Now Totes Intellisense</h4>
<p>You can download the XML schema file from <a href="http://www.weirdlover.com/chirpy/chirp.xsd">here</a>, or, if you&#8217;re lazy, you can reference the xsd file thusly:</p>
<pre>
<code class="html">
&lt;?xml version="1.0"?>

&lt;root
  xmlns="urn:ChirpyConfig"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="urn:ChirpyConfig http://www.weirdlover.com/chirpy/chirp.xsd">

  &lt;FileGroup Name="mash.js" Minify="False">
    &lt;File Path="jquery-1.4.2.min.js"/>
    &lt;File Path="json2.min.js"/>
  &lt;/FileGroup>

  &lt;FileGroup Name="mash.min.js" Minify="True">
    &lt;File Path="jquery-1.4.2.min.js"/>
  &lt;/FileGroup>
&lt;/root>
</code>
</pre>
<p>Once you&#8217;ve referenced the xsd file, you&#8217;ll get your oh-so-desired intellisense:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/09/Test.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/09/Test-e1283821856111.png" alt="Test e1283821856111 Chirpy to the XXXtreme   v1.0.0.5 Release (Party? NSFW? Eh? Eh?)" title="Test" width="700" height="415" class="alignnone size-full wp-image-513" /></a></p>
<hr/>
<p>That&#8217;s it! Once again, Chirpy says: <strong>Happy Coding!</strong></p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/05/Zippy.jpg"><img src="http://www.weirdlover.com/wp-content/uploads/2010/05/Zippy.jpg" alt="Zippy Chirpy to the XXXtreme   v1.0.0.5 Release (Party? NSFW? Eh? Eh?)" title="Zippy" width="355" height="451" class="aligncenter size-full wp-image-64" /></a>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.weirdlover.com/2010/09/07/chirpy-to-the-xxxtreme-v1-0-0-5-da-kine-release/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
		<item>
		<title>And Then, Under the Guise Of Jesusness, A &#8220;Fake&#8221; Twitter App Arose From the Spammy Ashes</title>
		<link>http://www.weirdlover.com/2010/08/23/and-then-under-the-guise-of-jesusness-a-fake-twitter-app-arose-from-the-spammy-ashes/</link>
		<comments>http://www.weirdlover.com/2010/08/23/and-then-under-the-guise-of-jesusness-a-fake-twitter-app-arose-from-the-spammy-ashes/#comments</comments>
		<pubDate>Mon, 23 Aug 2010 22:00:34 +0000</pubDate>
		<dc:creator>Evan</dc:creator>
				<category><![CDATA[Humor]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://www.weirdlover.com/?p=500</guid>
		<description><![CDATA[I must've been feeling lonely. Because "fake followers" seemed like a really intriguing concept.]]></description>
			<content:encoded><![CDATA[<p>On Friday, I happened upon this twitter post by my friend <a href="http://twitter.com/alvinashcraft">Alvin Ashcraft</a>:</p>
<blockquote><p>
<strong>alvinashcraft</strong> I have 162 fake followers, and you? http://twifakes.heroku.com/
</p></blockquote>
<p>I must&#8217;ve been feeling lonely. Because &#8220;fake followers&#8221; seemed like a really intriguing concept. It reminded me of a tweet written by <a href="http://twitter.com/shanselman">Scott Hanselman</a> a few days earlier:</p>
<blockquote><p>
<strong>shanselman</strong> Interesting little tidbit for you. Kevin Smith has 1.6 MILLION followers and tweets a lot. He RT&#8217;ed something of mine, and *crickets.*
</p></blockquote>
<p>I thought to myself, &#8220;How many of <em>my</em> followers are fake?&#8221; I mean, when I user twitter, it almost always feel like I&#8217;m taking a really long walk down a super lonely, cricket-laden pier. And, besides, if I could only find out exactly <em>how many</em> of my fake online friends/followers are <em>super-super-fake</em>, I might actually be able to stop <a href="http://www.urbandictionary.com/define.php?term=Googlebating">Googlbating</a> and <a href="http://slightlysarcastic.net/2010/04/no-more-peecrastinating-ive-got-a-urination-proclaimation/">peecrastinating</a>, at least for a minute or two.</p>
<p>In my moment of despair and self-loathing, in walk two Brazillian fellows. Meet: Cairo Noleto (<a href="caironoletoo">@caironoleto</a>) and Cleiton Francisco (<a href="http://twitter.com/cleitonfco">@cleitonfco</a>). They created an &#8220;open source&#8221; twitter application that &#8220;counts&#8221; the number of fake followers that are fakely following you. It&#8217;s called #TwiFakes, and it&#8217;s sweeping the fake twitter nation. </p>
<p>So, as I was staring lovingly at my Twitter page, I naively thought to myself, &#8220;If it&#8217;s good enough for Alvin Ashcraft to retweet about the #TwiFakes phenomenon, then it&#8217;s good enough for me to try!&#8221; And try I did. And, without my consent (which is of little use to anyone), #TwiFakes went ahead and FarmVilled me right in the face. My newest post, which I did not consent to, looked a lot like Alvin Ashcraft&#8217;s, except instead of 162 fakers, I had a measley 12:</p>
<blockquote><p>
<strong>evannagle</strong> I have 12 fake followers, and you? http://twifakes.heroku.com/
</p></blockquote>
<p>Flash forward a few days. Julie Lerman (<a href="http://twitter.com/julielerman">@julielerman</a>) falls victim to the same malicious Brazillian antics. Lucky for Julie, she has fewer fake followers than I do (proportionate to the total number), so one of her dedicated followers was kind enough to point her to Adrian Short&#8217;s <a href="http://adrianshort.co.uk/2010/08/20/how-to-deal-with-twifakes/">excellent TwiFakes post</a>. In it, Adrian offers the following bit of quasi-conspiratorial (albeit excellent) advice:</p>
<blockquote><p>
You may have seen the website at http://twifakes.heroku.com/ which promises to tell you how many â€œfakeâ€ Twitter followers you have. Do not authorise this website. It tweets without your permission and thereâ€™s no telling whether it may do other damage to your account.
</p></blockquote>
<p>Now, here&#8217;s the real kicker:</p>
<blockquote><p>
In case youâ€™re wondering, your number of â€œfakeâ€ followers is the number of followers you have divided by twelve. Hardcore algorithm.
</p></blockquote>
<p>And here&#8217;s how Cairo and Cleiton plead their case for their so-called algorithmic masterpiece:</p>
<blockquote><p>
In the Holy Bible, Jesus had 12 followers loyal to his cause, but among them was a fake that was the name of this apostle was Judas.</p>
<p>Following this logic, we conclude that every 12 that a person has followers on Twitter, one of them is fake.</p>
<p>Simply calculate the number of followers a person has and divide by 12, this result is the amount of people who are fake.
</p></blockquote>
<p>Flash forward to this very moment in time. Cairo and Cleiton&#8217;s devious invention is still sweeping the twitter nation, especially amongst the Portuguese-speaking population. (Interesting sidenote: it seems that black people [who virtually <a href="http://www.motherboard.tv/2010/8/19/how-black-people-use-twitter-words-that-lead-to-trouble--2">own Twitter</a>] have largely been spared). Though Cairo and Cleiton have removed the non-permissive tweet from their arsenal, their super-simple algorithm is still churning away behind the curtain of shame, and more and more desperate souls are selling their personal privacy for a possible quenching of their ever-increasing <a href="http://www.amazon.com/Reality-Hunger-Manifesto-David-Shields/dp/0307273539">hunger for reality</a>. </p>
<p>Aside from the obvious complaints I could make here&#8211;complaints that are well-detailed in Adrian&#8217;s post&#8211;I do believe that Cairo and Cleiton&#8217;s spamtastic app sheds some light on a fundamental twitterer&#8217;s desire. A desire for <em>fame</em> and <em>self-affirmation</em>, that is. Twitter, after all, is really a vehicle for micro-fame, as it allows non-Jesuses like myself to accrue exponentially more followers than Jesus ever did (to follow me, click <a href="http://www.twitter.com/evannagle">here</a>). And, admittedly, there&#8217;s something really pleasing about <em>writing a quick fetishized fragment of thought</em> and fantasizing about all the world salivating and retweeting it. </p>
<p>Time to get really, really real, then: Twitter is itself <em>not</em> a valid means of calculating self-worth. One&#8217;s &#8220;number&#8221; of &#8220;followers&#8221; is more like one&#8217;s &#8220;number&#8221; of &#8220;co-fantasizers&#8221;, and, sooner or later, we&#8217;re all going to wake up and realize that the internet, as social and as complex and as beautiful as it is, can&#8217;t really tell us <em>who we are</em> beause it&#8217;s way too busy catering to the people that we <em>want to pretend to be</em>. In other words, <em>all</em> of your followers are pretty much fake. No need for division, or frivolous spamming, or crucifixions. </p>
<p>Now, though I&#8217;m not a religious fellow by any means, I figure that a quote from Jesus might be in order:</p>
<blockquote><p>
If any of you wants to be my follower, you must turn from your selfish ways, take up your cross, and follow me. If you try to hang on to your life, you will lose it. But if you give up your life for my sake and for the sake of the Good News, you will save it. And what do you benefit if you gain the whole world but lose your own soul? Is anything worth more than your soul? If anyone is ashamed of me and my message in these adulterous and sinful days, the Son of Man will be ashamed of that person when he returns in the glory of his Father with the holy angels.
</p></blockquote>
<p>Or, the tweetable version:</p>
<blockquote><p>
<strong>jesuschrist</strong> #ff @jesuschrist
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.weirdlover.com/2010/08/23/and-then-under-the-guise-of-jesusness-a-fake-twitter-app-arose-from-the-spammy-ashes/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>The Big Boy MVC Series &#8212; Part 26: It&#8217;s Codeplex Time!</title>
		<link>http://www.weirdlover.com/2010/08/19/big-boy-mvc-part-26-its-codeplex-time/</link>
		<comments>http://www.weirdlover.com/2010/08/19/big-boy-mvc-part-26-its-codeplex-time/#comments</comments>
		<pubDate>Thu, 19 Aug 2010 23:26:54 +0000</pubDate>
		<dc:creator>Evan</dc:creator>
				<category><![CDATA[ASP.NET MVC]]></category>
		<category><![CDATA[Asp.Net MVC Tutorials (eng)]]></category>
		<category><![CDATA[Big Boy]]></category>
		<category><![CDATA[Giving Up]]></category>
		<category><![CDATA[MVC]]></category>

		<guid isPermaLink="false">http://www.weirdlover.com/?p=496</guid>
		<description><![CDATA[You've sucked all the blood out of me. Hence, the bottomless silence.  That said, I've finished creating a working version of Big Fat Dish. Joy almighty! Beer and Cool-aid-induced unconsciousness await!]]></description>
			<content:encoded><![CDATA[<p>New to <strong>The Big Boy MVC Series</strong>?<br />
Read the series from its <a href="http://www.weirdlover.com/2010/05/29/the-big-boy-mvc-series-building-an-asp-net-mvc-web-application-all-by-yourself-part-1/"><strong>humble beginnings</strong></a>.</p>
<hr/>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/08/True_Blood_by_IslaDelCoco1.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/08/True_Blood_by_IslaDelCoco1-e1282102011279.png" alt="True Blood by IslaDelCoco1 e1282102011279 The Big Boy MVC Series    Part 26: Its Codeplex Time!" title="True_Blood_by_IslaDelCoco" width="700" height="557" class="alignnone size-full wp-image-497" /></a></p>
<p>You&#8217;ve sucked all the blood out of me. Hence, the bottomless silence.</p>
<p>That said, I&#8217;ve finished creating a working version of Big Fat Dish. Joy almighty! Beer and Cool-aid-induced unconsciousness await!</p>
<p>Now, don&#8217;t get too excited. The site is nowhere NEAR perfect (unlike my looks). And I haven&#8217;t finished everything that I set out to finish. Not even close. But the project&#8217;s not crappy. And I have plenty more blogging to do (though the 25 posts I&#8217;ve written thus far will have to suffice as the &#8216;in-depth&#8217; portion of this experiment, at least for now). I&#8217;ve gotten some great feedback from the community (a huge thanks to everyone), and I think it&#8217;s time that the &#8220;Big Boy MVC series&#8221; finally became more of a, eh, community experiment. In short: help me.</p>
<p>Hopefully, if you&#8217;ve been following along, you&#8217;ve learned a decent amount about MVC (while also enjoying my self-effacing jokes). Now, since my hair and my patience are growing thinner, and since you&#8217;ve surely grown into a hair-greased MVC pro by now, it&#8217;s time that YOU teach ME something. That&#8217;s right. Teach me anything. Do it. I dare you. Wise-cracking and smack-talking can only get you so far. So, have at it.</p>
<p>Okay. Anyways. Here&#8217;s the idea:</p>
<ul>
<li>Download <strong>Big Fat Dish</strong>. You can grab the source code <a href="http://bfd.codeplex.com/">here</a></li>
<li>Fiddle around with the source code. Add new features. Fix crappy features. Add crappy features. Keep in  mind: I&#8217;m using the term &#8220;feature&#8221; loosely here. Add WHATEVER suits your fancy (design, code, copy, coffee stains, WHATEVER). In essence, start learning/doing crap on your own. Like my ex-girlfriend always used to tell me: some time apart will be good for our relationship. So, spend some time by yourself, create something cool, and get back to  me.</li>
<li>If you think that your addition/s to the project might be worthwhile to others then I beg you to blog about what you&#8217;ve done. Or, at the very least, make a pull request, and I&#8217;ll be sure to add your changes to the main project.</li>
<li>If I like your addition (which I probably will), and if the addition is substantial enough (which it probably will be), I&#8217;ll add you as a developer on the project. If you are a developer on any of the project, I consider you a lifelong friend. I will divert bullets for you. I will also respond to your emails in a timely fashion.</li>
<li>Most importantly, have fun. And don&#8217;t be evil. And don&#8217;t cry. I&#8217;m excited to learn some new tricks. And I&#8217;m excited to see what kind of website is brought forth from the OSS ether.</li>
</ul>
<p>A quote from the Codeplex page, which sums it up methinks:</p>
<blockquote><p>
In its current state, the project is well-formed but severely lacking in all kinds of digital coolness (features, styling, logo, love-making, etc). As a natural extension of the Big Boy MVC series, the Codeplex project will serve as a community-oriented means of continued MVC learning. If you&#8217;re new to MVC, or if you&#8217;re a sleazy MVC master, this project is a great sandbox for feature-testing and crap-flinging.
</p></blockquote>
<p>Alrighty. That&#8217;s all for now! I&#8217;m excited to see what kind of madness ensues! Happy coding!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.weirdlover.com/2010/08/19/big-boy-mvc-part-26-its-codeplex-time/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Microsoft.Data &#8212; Let&#8217;s Inject Some Love Into the Conversation</title>
		<link>http://www.weirdlover.com/2010/08/03/microsoft-data-lets-inject-some-love-into-the-conversation/</link>
		<comments>http://www.weirdlover.com/2010/08/03/microsoft-data-lets-inject-some-love-into-the-conversation/#comments</comments>
		<pubDate>Tue, 03 Aug 2010 21:46:35 +0000</pubDate>
		<dc:creator>Evan</dc:creator>
				<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Humor]]></category>
		<category><![CDATA[Microsoft.Data]]></category>

		<guid isPermaLink="false">http://www.weirdlover.com/?p=490</guid>
		<description><![CDATA[Okay. So, if you live in the bowels of a horse, or if you were too busy watching reruns of Rubicon and Mad Men last night, you probably missed all of the chaos surrounding the upcoming release of the Microsoft.Data library. To recap: it started with <a href="http://weblogs.asp.net/davidfowler/archive/2010/08/02/introduction-to-microsoft-data-dll.aspx">this innocent little blog post</a> by David Fowler.]]></description>
			<content:encoded><![CDATA[<p>Okay. So, if you live in the bowels of a horse, or if you were too busy watching reruns of Rubicon and Mad Men last night, you probably missed all of the chaos surrounding the upcoming release of the Microsoft.Data library. To recap: it started with <a href="http://weblogs.asp.net/davidfowler/archive/2010/08/02/introduction-to-microsoft-data-dll.aspx">this innocent little blog post</a> by David Fowler. An excerpt:</p>
<blockquote><p>
Itâ€™s an awesome new assembly/namespace that contains everything youâ€™ll ever need to access a database. In ASP.NET WebPages we wanted people to be able to access the database without having to write too many lines of code. Any developer that has used raw ADO.NET knows this pain:</p>
<pre>
<code class="csharp">
using (var connection = new SqlConnection(@"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Northwind.mdf;
                                           Initial Catalog=|DataDirectory|\Northwind.mdf;Integrated Security=True;User Instance=True")) {
    using (var command = new SqlCommand("select * from products where UnitsInStock < 20", connection)) {
        connection.Open();
        using (SqlDataReader reader = command.ExecuteReader()) {
            while (reader.Read()) {
                Response.Write(reader["ProductName"] + " " + reader["UnitsInStock"]);
            }
        }
    }
}
</code>
</pre>
<p>Wow, thatâ€™s a lot of code compared to:</p>
<pre>
<code class="csharp">
using (var db = Database.OpenFile("Northwind")) {
    foreach (var product in db.Query("select * from products where UnitsInStock < 20")) {
        Response.Write(product.ProductName + " " + product.UnitsInStock);
    }
}
</code>
</pre>
</blockquote>
<p>Shortly thereafter, Rob Conery had this to say:</p>
<blockquote><p>
Data Acess is hard! Let's go shopping! http://bit.ly/cbO9Kh - we've been down this road, oh so many times.
</p></blockquote>
<p>Then, Oren Eini  wrote <a href="http://ayende.com/blog/default.aspx">this scathing response</a>. An excerpt:</p>
<blockquote><p>
I really donâ€™t know where to start. Yes, compared to raw ADO.Net I guess that this is improvement. But being beaten only thrice a week instead of daily is also an improvement.</p>
<p>I mean, seriously, are you freaking kidding me? Are you telling me that you are aiming to make the life of people writing code like this easier?
</p></blockquote>
<p>Then, a baby calf was born.</p>
<p>Then, a bunch of developers started tweeting and making jokes at Microsoft.Data's expense!</p>
<p>Then, Andrew Nurse (one of the creators of <a href="http://channel9.msdn.com/shows/Going+Deep/Andrew-Nurse-Inside-Razor/">Razor</a>), wrote <a href="http://blog.andrewnurse.net/">this defense</a>. An excerpt:</p>
<blockquote><p>
David Fowler, fellow ASP.Net team member, posted about it earlier today, and the response has been â€¦ active.  The message behind most of these responses has been that it encourages bad practices to novice developers.  I think thereâ€™s an important point thatâ€™s being missed here: It doesnâ€™t matter how hard we work, as professional developers, to create clean architectures and abstractions, thereâ€™s a whole world of novice developers who just donâ€™t care about that.  They want to write code now and be done with it.  This is the audience targeted by Microsoft.Data, and the WebMatrix product as a whole.
</p></blockquote>
<p>Then, David Fowler wrote a <a href="http://weblogs.asp.net/davidfowler/archive/2010/08/03/microsoft-data-dll-a-re-introduction.aspx">follow-up post</a>. In it, he clarified (perhaps fearful for his life, and the lives of his unborn children...):</p>
<blockquote><p>
These blog posts point out that WebMatrix targets a different audience than our traditional pro developer audience. These are people who are not yet developers (if they ever plan to be). They may never want to become a pro developer, but want to be able to put together a simple website. If you've internalized best practices and patterns and know your way around an ORM, then you will most likely never use this library. We are trying to attract a different kind of customer: people who are on other platforms and are already using SQL today in their web pages, and people that are trying to get into programming and havenâ€™t chosen a platform as yet.</p>
<p>Most likely, if you're even reading this, you're not the intended audience, though we are still interested in your feedback.
</p></blockquote>
<p>Then, my friend, David Ebbo, <a href="http://blogs.msdn.com/b/davidebb/archive/2010/08/03/a-short-take-on-microsoft-data.aspx?wa=wsignin1.0">chimed in</a>:</p>
<blockquote><p>
As great as ORMs are, there is a measurable number of web developers who favor writing raw SQL over using an ORM.  Now you may not think highly of people in that camp, but if youâ€™re trying to pretend that they donâ€™t exist, youâ€™re in denial.  Though they tend to be less vocal, there are a lot of people who prefer this approach, for a variety of reasons.  They could be â€˜SQL gurusâ€™ who like full control, or more likely they are not experienced programmers, and all the OOP that come with ORMs are just not for them.
</p></blockquote>
<p>Then, Andrew Nurse, Scott Gu, and Rob Conery started fighting (with <em>words</em>) on Twitter. </p>
<p>Then, other stuff happened.</p>
<p>Then, my mom called me.</p>
<p>Then, after all the punch in the punch bowl had already been consumed and regurgitated, I started writing this very post.  It's too late to save anyone. Or to say anything interesting. But I might be able to bring a little bit of comic relief to the battle zone. We'll see. Here comes the meta.</p>
<hr/>
<p>So, let's take a breath, and, before we punch anybody, let's reflect. </p>
<p>Okay. Reflection over. Now, let me shamelessly divulge my reflection-conjured thoughts. </p>
<h3>Thought 1: Microsoft.Data is a bad name for a namespace. It's too generic, and novice developers won't be able to find documentation via a simple google search.</h3>
<p> Instead of "Data", a name prefixed by ADO might be better, as it would be much easier to search for, and would be more likely to inspire the "novice" developer to get better acquainted with the ADO technology that he's fiddling with. "Data" is too myopic, especially for a library that serves as a light ADO wrapper.</p>
<h3>Thought 2: Microsoft's response to the outcry is misguided. The anger is cultural, not technical.</h3>
<p> Yes; everyone knows that Microsoft constructed WebMatrix, Razor, and Microsoft.Data as part of a pointed campaign to entice novice developers (and stupid people) into flocking to the pricey Microsoft stack. And, yes; the Microsoft.Data library will surely be a helpful library for those developers who want to throw a website together without thinking too much about the architecture of what they're constructing. Technically (and commercially) speaking, Microsoft has a slew of <em>perfectly legitimate</em> reasons for splattering the landscape with these "watered down" technologies. But, <em>culturally speaking</em>, it's painful to the professional Microsoft developer. It is. Because the Microsoft developer's personal and professional identity is tied up in the Microsoft stack, and that stack is now catering to a bunch of cat ladies and acne-laden teenagers. <em>That's</em> the real issue here.</p>
<p>To put this point another way, let's talk about the <strike>now</strike>NEVER-defunct band, Tool. Let's say that, out of the blue, Tool decided to write a song about the importance of loving lambs and feeling all "gushy inside". A "professional" Tool fan would surely be outraged--not because Tool had done something stupid on a functional (i.e. musical) level, but because Tool had lost its sense of direction, and had thus muddied the waters that once helped the Tool fan construct and reinforce his/her identity. And, all the while, Tool frontman, Maynard James Keenan, only had this to say:</p>
<blockquote><p>
I think thereâ€™s an important point thatâ€™s being missed here: It doesnâ€™t matter how hard we work, as professional musicians, to create hardcore sounds and abstractions, thereâ€™s a whole world of teenie boppers who just donâ€™t care about that.
</p></blockquote>
<h3>Thought 3: Shakespeare had it right.</h3>
<p> Every Shakespeare play operates on <em>three levels</em>. The first level is embodied in a jester, who entertains the onlookers (mostly children) who are ill-equipped to understand what's going on in the plot. The second level is the plot, which entertains the onlookers who are capable of longer spurts of self-guided attention. And the third level is metaphorical, which entertains the onlookers who are capable of extracting  a bottomless stream of interesting, non-explicit symbolic themes from the play's unraveling. Now, here's the kicker of it all: each level <em>entices</em> the onlooker to "upgrade" to the next level. </p>
<p>To put this another way: Shakespeare didn't employ the jester just to let stupid people off the hook. The jester prods the stupid onlooker into deeper contemplation. Isaac Asimov chimes in with this tidbit of interest about the function of the Shakespearean jester:</p>
<blockquote><p>
Some have argued that the clowning in Shakespeare's plays may have been intended as "an emotional vacation from the more serious business of the main action". Clowning scenes in Shakespeare's tragedies mostly appear straight after a truly horrific scene: The Gravediggers in Hamlet after Ophelia's suicide; The Porter in Macbeth just after the murder of the King; and as Cleopatra prepares herself for death in Antony and Cleopatra. Nevertheless, it is argued that Shakespeare's clowning goes beyond just 'comic relief', instead making the horrific or deeply complex scenes more understandable and "true to the realities of living, then and now" by shifting the focus from the fictional world to the audience's reality and thereby conveying "more effectively the theme of the drama."
</p></blockquote>
<p>So, for me, that's the real question here--namely, is WebMatrix (and, by extension, Microsoft.Data) just a space for stupid people to clown around and be perpetually and bottomlessly stupid? Or is it a means to <em>attempt to</em> help new developers attain a better grasp of the fundamentals of software development? Judging by the defeatist attitude of some of the Microsoft bloggers thus far (with sentiments like "people who will <em>never</em> be x"), I fear that the answer might be the former.</p>
<h3>Thought 4: This isn't the end of the world. There are people starving. There are wars. There are women being traded as sex slaves right outside my window in Honolulu. In sum, Microsoft.Data isn't responsible for the totality of all human suffering.</h3>
<p> Look, I understand that it's painful to watch a company like Microsoft cater to developers (i.e. old ladies) who aren't as technically proficient as "professional" developers are, but that's really no reason to rant about how "stupid" the world is (my own hypocrisy is intended here) and how "Microsoft fucks everything up". The reality is: not everyone can do the things that you can do, or learn the things that you so easily learned. And you should be proud of that. No need to lash out. Your prowess makes you special. You don't need Microsoft.Data to make your websites hum. And you'll surely get paid a good salary to fix the websites that do. So spend your energies fixing a real problem, like your crumbling relationship with your wife, or world hunger, or your T.V. set.</p>
<h3>Thought 5: As a Microsoft developer, you have to trust Microsoft. You have to give up the need for cultural affirmation. You have to believe that Jesus is a Microsoft employee.</h3>
<p> Culturally, OSS will beat Microsoft any day of the week. Because OSS is like love (sex for free), and Microsoft is like prostitution (sex for money). Love is definitely nicer (or "gushier"), but prostitution is a stabler source of long-term sexual relations. And that's the trade off you're making as a Microsoft developer. In twenty years, you know that Microsoft will still be pimpin' <em>something</em> nerdy, but RoR might be an abandoned ghost town full of broken twitter-like applications. Probably not, but who knows. After all, when something's free, it's beautiful. But it's more likely to flee. Whether that's a good thing or a bad thing, that's up to you to decide.</p>
<hr/>
<p>So, those are my thoughts for now. </p>
<p>Play dramatic music here.</p>
<p>Close curtains.</p>
<p>Cue flaming comments.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.weirdlover.com/2010/08/03/microsoft-data-lets-inject-some-love-into-the-conversation/feed/</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>Prototypal C#: Making C# Look and Work Like JavaScript</title>
		<link>http://www.weirdlover.com/2010/07/26/prototypal-c-making-c-look-and-work-like-javascript/</link>
		<comments>http://www.weirdlover.com/2010/07/26/prototypal-c-making-c-look-and-work-like-javascript/#comments</comments>
		<pubDate>Mon, 26 Jul 2010 06:13:07 +0000</pubDate>
		<dc:creator>Evan</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[C# 4.0]]></category>
		<category><![CDATA[Dynamic]]></category>

		<guid isPermaLink="false">http://www.weirdlover.com/?p=486</guid>
		<description><![CDATA[If you don't know much about <strong>prototypal inheritence</strong>, no worries. For starters, check out Douglas Crockford's super-short <a href="http://javascript.crockford.com/prototypal.html">germinal article</a> on the subject. Then, watch Crockford wax prototypical in this excellent (albeit somewhat boring) <a href="http://developer.yahoo.com/yui/theater/video.php?v=crockonjs-3">Yahoo presentation</a>. Then, if you're still hungry for more, read the Wikipedia article about Prototype-based programming <a href="http://en.wikipedia.org/wiki/Prototype-based_programming">here</a>. And, finally, if you're a fan of example-based learning, go ahead and watch this excellent Google video on <a href="http://www.youtube.com/watch?v=s4Lppyuu4nI">Advanced JavaScript techniques</a>.]]></description>
			<content:encoded><![CDATA[<p>If you don&#8217;t know much about <strong>prototypal inheritence</strong>, no worries. For starters, check out Douglas Crockford&#8217;s super-short <a href="http://javascript.crockford.com/prototypal.html">germinal article</a> on the subject. Then, watch Crockford wax prototypical in this excellent (albeit somewhat boring) <a href="http://developer.yahoo.com/yui/theater/video.php?v=crockonjs-3">Yahoo presentation</a>. Then, if you&#8217;re still hungry for more, read the Wikipedia article about Prototype-based programming <a href="http://en.wikipedia.org/wiki/Prototype-based_programming">here</a>. And, finally, if you&#8217;re a fan of example-based learning, go ahead and watch this excellent Google video on <a href="http://www.youtube.com/watch?v=s4Lppyuu4nI">Advanced JavaScript techniques</a>.</p>
<p>Wrapped your head around the concept yet? Good. Let&#8217;s begin by taking a quick look at a simple example of prototypal inheritance in JavaScript. This example comes from Tim Caswell&#8217;s aptly named post, <a href="http://howtonode.org/prototypical-inheritance">Prototypal Inheritance</a>. If you&#8217;re familiar with JavaScript, this snippet of code should seem pretty trivial. </p>
<pre>
<code class="javascript">
var Animal = {
  eyes: 2,
  legs: 4,
  name: "Animal",
  toString: function () {
    return this.name + " with " + this.eyes + " eyes and " + this.legs + " legs."
  }
}

var Dog = Animal.spawn({
  name: "Dog"
});

var Insect = Animal.spawn({
  name: "Insect",
  legs: 6
});

var fred = Dog.spawn({});
var pete = Insect.spawn({});

sys.puts(fred);
sys.puts(pete);
</code>
</pre>
<p>Using anonymous types in C# 3.0, we could <em>almost</em> recreate an Animal object in the exact same manner that we created the JavaScript Animal above&#8211;that is, with one glaring and obvious exception: the <strong><em>this</em></strong> in the <strong>toString</strong> function. C# 3.0 will have none of it:</p>
<pre>
<code class="csharp">
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Protopal.Tests.Core
{
    [TestClass]
    public class ProtoTest
    {
        [TestMethod]
        public void Proto_Sandbox_Try_To_Create_JavaScript_Ish_Object()
        {
            var Animal = new
            {
                eyes = 2,
                legs = 4,
                name = "Animal",
                toString = (Func&lt;string>)(() =>
                    this.Name + " with " + this.Eyes + " eyes and " + this.Legs + " legs.")
            };
        }
    }
}
</code>
</pre>
<p>The compiler resolves the &#8220;this&#8221; to Protopal.Tests.Core.ProtoTest (as it should). And, since the ProtoTest class contains no definition for <strong>name</strong>, <strong>eyes</strong>, or <strong>legs</strong>, the compiler lets us feel its wrath:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/compiler-wrath.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/compiler-wrath-e1280096576438.png" alt="compiler wrath e1280096576438 Prototypal C#: Making C# Look and Work Like JavaScript" title="compiler wrath" width="700" height="416" class="alignnone size-full wp-image-487" /></a></p>
<p>In C# 4.0, the <strong>dynamic type</strong> offers us an interesting workaround. For starters, we can create the following delegates&#8211;each of which contains a dynamically typed first parameter. More on that in a second:</p>
<pre>
<code class="csharp">
namespace Protopal.Core
{
    public delegate TR PFunc&lt;TR>(dynamic me);
    public delegate TR PFunc&lt;T1, TR>(dynamic me, T1 arg1);
    public delegate TR PFunc&lt;T1, T2, TR>(dynamic me, T1 arg1, T2 arg2);
    public delegate TR PFunc&lt;T1, T2, T3, TR>(dynamic me, T1 arg1, T2 arg2, T3 arg3);

    //and the allstars...
}
</code>
</pre>
<p>Okay. We&#8217;re getting closer. Let&#8217;s go ahead and rework our Animal object so it compiles. Notice that we&#8217;re now setting the <strong>toString</strong> property to a PFunc instead of a Func, and in our PFunc, by convention, we&#8217;re assuming that the first passed parameter will be resolved to our not-yet-defined anonymous type (i.e. the &#8220;this&#8221; we wanted all along):</p>
<pre>
<code class="csharp">
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Protopal.Core;

namespace Protopal.Tests.Core
{
    [TestClass]
    public class ProtoTest
    {
        [TestMethod]
        public void Proto_Sandbox_Try_To_Create_JavaScript_Ish_Object()
        {
            var Animal = new
            {
                eyes = 2,
                legs = 4,
                name = "Animal",
                toString = (PFunc&lt;string>)
                    (me => me.name + " with " + me.eyes + " eyes and " + me.legs + " legs.")
            };
        }
    }
}
</code>
</pre>
<p>Now, we can feed our Animal object back into the toString() function and retrieve the string that we&#8217;d expect. Granted, this initial solution is uglier than any woman that I&#8217;ve ever dated (only by a little), but at least it works. Don&#8217;t cringe yet, friend. We&#8217;ll make it much, much prettier in just a moment:</p>
<pre>
<code class="csharp">
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Protopal.Core;

namespace Protopal.Tests.Core
{
    [TestClass]
    public class ProtoTest
    {
        [TestMethod]
        public void Proto_Sandbox_Try_To_Create_JavaScript_Ish_Object()
        {
            var Animal = new
            {
                eyes = 2,
                legs = 4,
                name = "Animal",
                toString = (PFunc&lt;string>)
                    (me => me.name + " with " + me.eyes + " eyes and " + me.legs + " legs.")
            };

            Assert.AreEqual("Animal with 2 eyes and 4 legs.", Animal.toString(Animal));
        }
    }
}
</code>
</pre>
<p>Yes, it works, but that kind of ugliness won&#8217;t do. We can definitely do better. </p>
<p>Let&#8217;s start by creating our own <a href="http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.aspx">DynamicObject</a> class. We&#8217;ll call our class <strong>Proto</strong>.  Proto will be very similar to <a href="http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx">ExpandoObject</a> (which also derives from the DynamicObject class). The main difference: when a user invokes a PFunc delegate on a Proto class, we&#8217;ll intercept the call and  insert the Proto class as the first argument.</p>
<p>Before I reveal the Proto class, let me preface the following code with two important sentiments. First, I&#8217;m just screwing around here. I think that a Proto-ish class could really be useful in certain situations, but I <em>don&#8217;t</em> share Rob Conery&#8217;s inner desire to DuckDiaper and Rubify <em>everything</em>. Second, as you&#8217;ll hopefully notice, the DynamicObject class is amazingly and dangerously flexible&#8211;so flexible, in fact, that you can really force the dynamic type to do whatever the heck you want, even if the thing you want to do is really, really stupid. So, beware. And don&#8217;t blame me if your boss fires you.</p>
<pre>
<code class="csharp">
using System;
using System.Linq;
using System.Collections.Generic;
using System.Dynamic;

namespace Protopal.Core
{
    public sealed class Proto : DynamicObject
    {

        Dictionary&lt;string, object> members;

        object obj;

        public static dynamic Pal(object members)
        {
            return new Proto(members);
        }

        Proto(object members)
        {
            if (members == null)
            {
                this.members = new Dictionary&lt;string, object>();
                this.obj = new object { };
            }
            else
            {
                this.obj = members;
                Type objType = this.obj.GetType();

                if (objType == typeof(Proto))
                {
                    Proto parent = (Proto)this.obj;
                    this.members = new Dictionary&lt;string, object>(parent.members);
                }
                else
                {
                    this.members = objType
                        .GetProperties()
                        .ToDictionary(k => k.Name, v => v.GetValue(members, null));
                }
            }
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            members[binder.Name] = value;
            return true;
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            if (members.TryGetValue(binder.Name, out result))
            {
                return true;
            }
            else
            {
                result = new Proto(new object { });
                members[binder.Name] = result;
                return true;
            }
        }

        public override bool TryInvokeMember(InvokeMemberBinder binder,
            object[] args, out object result)
        {
            object member;

            if (members.TryGetValue(binder.Name, out member))
            {
                Type memberType = member.GetType();

                if (memberType.IsGenericType)
                {
                    var genericType = memberType.GetGenericTypeDefinition();

                    if (genericType == typeof(PFunc&lt;>) ||
                        genericType == typeof(PFunc&lt;,>) ||
                        genericType == typeof(PFunc&lt;,,>) ||
                        genericType == typeof(PFunc&lt;,,,>))
                    {
                        var del = member as Delegate;

                        var delArgs = new List&lt;object>();
                        delArgs.Add(this);
                        delArgs.AddRange(args);

                        result = del.DynamicInvoke(delArgs.ToArray());
                        return true;
                    }
                }
            }

            return base.TryInvokeMember(binder, args, out result);
        }
    }
}
</code>
</pre>
<p>Now, let&#8217;s reconfigure our test:</p>
<pre>
<code class="csharp">
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Protopal.Core;

namespace Protopal.Tests.Core
{
    [TestClass]
    public class ProtoTest
    {
        [TestMethod]
        public void Proto_Sandbox_Try_To_Create_JavaScript_Ish_Object()
        {
            var Animal = Proto.Pal(new
            {
                eyes = 2,
                legs = 4,
                name = "Animal",
                toString = (PFunc&lt;string>)
                    (me => me.name + " with " + me.eyes + " eyes and " + me.legs + " legs.")
            });

            Assert.AreEqual("Animal with 2 eyes and 4 legs.", Animal.toString());
        }
    }
}
</code>
</pre>
<p>That works. Coolness. Cookies for all!</p>
<p>Okay, okay. Let&#8217;s not congratulate ourselves just quite yet. What about &#8220;spawning&#8221; all kinds of child classes from our Animal object&#8211;you know, like in good ol&#8217; JavaScript? Hmm. Good question. </p>
<p>For starters, if we <em>really</em> want to accomplish this feat, we have to create an extension method for merging together dictionaries. I swiped this bit of code form <a href="http://stackoverflow.com/questions/294138/merging-dictionaries-in-c">StackOverflow</a>:</p>
<pre>
<code class="csharp">
using System.Collections.Generic;
using System.Linq;

namespace Protopal.Extensions
{
    public static class DictionaryExtensions
    {
        public static T MergeLeft&lt;T, K, V>(this T me, params IDictionary&lt;K, V>[] others)
            where T : IDictionary&lt;K, V>, new()
        {
            T newMap = new T();
            foreach (IDictionary&lt;K, V> src in
                (new List<IDictionary&lt;K, V>> { me }).Concat(others))
            {
                foreach (KeyValuePair&lt;K, V> p in src)
                {
                    newMap[p.Key] = p.Value;
                }
            }
            return newMap;
        }
    }
}
</code>
</pre>
<p>Now, we can add a public <strong>Spawn</strong> method to our Proto class:</p>
<pre>
<code class="csharp">
using System;
using System.Linq;
using System.Collections.Generic;
using System.Dynamic;
using Protopal.Extensions;

namespace Protopal.Core
{
    public sealed class Proto : DynamicObject
    {

        Dictionary&lt;string, object> members;

        object obj;

        public static dynamic Pal(object members)
        {
            return new Proto(members);
        }

        Proto(object members)
        {
            if (members == null)
            {
                this.members = new Dictionary&lt;string, object>();
                this.obj = new object { };
            }
            else
            {
                this.obj = members;
                Type objType = this.obj.GetType();

                if (objType == typeof(Proto))
                {
                    Proto parent = (Proto)this.obj;
                    this.members = new Dictionary&lt;string, object>(parent.members);
                }
                else
                {
                    this.members = objType
                        .GetProperties()
                        .ToDictionary(k => k.Name, v => v.GetValue(members, null));
                }
            }
        }

        public dynamic Spawn(object members)
        {
            var pal = new Proto(members);
            pal.members = this.members.MergeLeft(pal.members);

            return pal;
        } 

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            members[binder.Name] = value;
            return true;
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            if (members.TryGetValue(binder.Name, out result))
            {
                return true;
            }
            else
            {
                result = new Proto(new object { });
                members[binder.Name] = result;
                return true;
            }
        }

        public override bool TryInvokeMember(InvokeMemberBinder binder,
            object[] args, out object result)
        {
            object member;

            if (members.TryGetValue(binder.Name, out member))
            {
                Type memberType = member.GetType();

                if (memberType.IsGenericType)
                {
                    var genericType = memberType.GetGenericTypeDefinition();

                    if (genericType == typeof(PFunc&lt;>) ||
                        genericType == typeof(PFunc&lt;,>) ||
                        genericType == typeof(PFunc&lt;,,>) ||
                        genericType == typeof(PFunc&lt;,,,>))
                    {
                        var del = member as Delegate;

                        var delArgs = new List&lt;object>();
                        delArgs.Add(this);
                        delArgs.AddRange(args);

                        result = del.DynamicInvoke(delArgs.ToArray());
                        return true;
                    }
                }
            }

            return base.TryInvokeMember(binder, args, out result);
        }
    }
}
</code>
</pre>
<p>And, for the long-awaited finale, here&#8217;s some quasi-prototypal C#, which functions just as well (sans any possible issues of so-called &#8220;performance&#8221;) as Tim Caswell&#8217;s prototypal JavaScript code:</p>
<pre>
<code class="csharp">
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Protopal.Core;

namespace Protopal.Tests.Core
{
    [TestClass]
    public class ProtoTest
    {
        [TestMethod]
        public void Proto_Sandbox_Try_To_Create_JavaScript_Ish_Object()
        {
            var Animal = Proto.Pal(new
            {
                eyes = 2,
                legs = 4,
                name = "Animal",
                toString = (PFunc&lt;string>)
                    (me => me.name + " with " + me.eyes + " eyes and " + me.legs + " legs.")
            });

            var Dog = Animal.Spawn(new
            {
                name = "Dog"
            });

            var Insect = Animal.Spawn(new
            {
                name = "Insect",
                legs = 6
            });

            var fred = Dog.Spawn(new {});
            var pete = Insect.Spawn(new {});

            Console.WriteLine(Animal.toString());
            Console.WriteLine(Dog.toString());
            Console.WriteLine(Insect.toString());
            Console.WriteLine(fred.toString());
            Console.WriteLine(pete.toString());
        }
    }
}
</code>
</pre>
<p>Looks like all of our animals are happy in their pens, which is nice:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/animal-dog-insect.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/animal-dog-insect-e1280100311691.png" alt="animal dog insect e1280100311691 Prototypal C#: Making C# Look and Work Like JavaScript" title="animal dog insect" width="700" height="416" class="alignnone size-full wp-image-488" /></a><br />
<br/></p>
<h2>Extra Credit</h2>
<p>Interestingly enough, the Protopal class yields a couple of cool (and quasi-unintended) side benefits. For starters, we can &#8220;change&#8221; the values of properties in anonymous types. For example:</p>
<pre>
<code class="csharp">
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Protopal.Core;

namespace Protopal.Tests.Core
{
    [TestClass]
    public class ProtoTest
    {
        [TestMethod]
        public void Proto_Sandbox_Try_To_Set_Anon_Type_Property()
        {
            var Animal = new
            {
                Name = "Animal"
            };

            //This is an error:
            //Animal.Name = "Manimal";

            var animalHijacked = Proto.Pal(Animal);
            animalHijacked.Name = "Manimal";

            Assert.AreEqual("Manimal", animalHijacked.Name);
        }
    }
}
</code>
</pre>
<p>Also, you can implement interesting IOC patterns, like this whopper:</p>
<pre>
<code class="csharp">
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Protopal.Core;

namespace Protopal.Tests.Core
{
    [TestClass]
    public class ProtoTest
    {
        [TestMethod]
        public void Proto_Sandbox_Reference_Property_That_Doesnt_Exist()
        {
            var evan = new
            {
                Name = "Evan"
            };

            var jaimie = new
            {
                Name = "Jaimie"
            };

            var sayer = Proto.Pal(new
            {
                Say = (PFunc&lt;string, string>)
                    ((me, x) => me.Name + " says, '" + x + "'")
            });

            string jaimieSays = sayer.Spawn(jaimie).Say("wudup");
            string evanSays = sayer.Spawn(evan).Say("yo yo");

            Assert.AreEqual("Jaimie says, 'wudup'", jaimieSays);
            Assert.AreEqual("Evan says, 'yo yo'", evanSays);
        }
    }
}
</code>
</pre>
<p>And that&#8217;s really just the tip of an extremely precarious iceberg&#8230;</p>
<h2>What Now?</h2>
<p>Sleep. Then, breakfast.</p>
<p>I think that this is an interesting, if not a super-stupid, POC. Surely, with a little bit of elbow grease and a hefty dose of refinement, a class like Protopal could really serve some kind of useful purpose. Maybe? Eh, I don&#8217;t know. Maybe you have a better idea of what that &#8220;purpose&#8221; might be (if anything). For now, I&#8217;ll leave the iceberg as it is, and let you chime in.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.weirdlover.com/2010/07/26/prototypal-c-making-c-look-and-work-like-javascript/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>The Big Boy MVC Series &#8212; Part 25, Going Postal: ActionFilters, Moq, ModelState, Oh My!</title>
		<link>http://www.weirdlover.com/2010/07/21/the-big-boy-mvc-series-part-25-going-postal-actionfilters-moq-modelstate-oh-my/</link>
		<comments>http://www.weirdlover.com/2010/07/21/the-big-boy-mvc-series-part-25-going-postal-actionfilters-moq-modelstate-oh-my/#comments</comments>
		<pubDate>Wed, 21 Jul 2010 11:35:40 +0000</pubDate>
		<dc:creator>Evan</dc:creator>
				<category><![CDATA[Big Boy MVC]]></category>
		<category><![CDATA[ActionFilters]]></category>
		<category><![CDATA[Big Boy]]></category>
		<category><![CDATA[ModelState]]></category>
		<category><![CDATA[Moq]]></category>
		<category><![CDATA[RedirectAction]]></category>
		<category><![CDATA[TempData]]></category>

		<guid isPermaLink="false">http://www.weirdlover.com/?p=448</guid>
		<description><![CDATA[The Bad News: I'm behind schedule. I wanted to finish this project in a month, and, if you've been paying close attention to the time I've wasted fiddling with the project, you'd know that I'm a week past my deadline. I'm not mad, or ashamed, or crying. Please don't make fun of me.]]></description>
			<content:encoded><![CDATA[<p>New to <strong>The Big Boy MVC Series</strong>?<br />
Read the series from its <a href="http://www.weirdlover.com/2010/05/29/the-big-boy-mvc-series-building-an-asp-net-mvc-web-application-all-by-yourself-part-1/"><strong>humble beginnings</strong></a>.</p>
<hr/>
<p>The good news: in my <a href="http://www.weirdlover.com/2010/07/15/the-big-boy-mvc-series-part-24-dear-editortemplates-are-we-done-posting-yet/">last Big Boy post</a>, we created a prettyish design-friendly EditorTemplate. That was fun. So, with our EditorTemplate completed, our FoodAdd page is looking all dolled up and decently man-spiffy:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/EditorTemplate-Designed-e1279167912422.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/EditorTemplate-Designed-e1279167912422.png" alt="EditorTemplate Designed e1279167912422 The Big Boy MVC Series    Part 25, Going Postal: ActionFilters, Moq, ModelState, Oh My!" title="EditorTemplate Designed" width="700" height="416" class="alignleft size-full wp-image-445" /></a></p>
<p>The Bad News: I&#8217;m behind schedule. I wanted to finish this project in a month, and, if you&#8217;ve been paying close attention to the time I&#8217;ve wasted fiddling with the project, you&#8217;d know that I&#8217;m a week past my deadline. I&#8217;m not mad, or ashamed, or crying. Please don&#8217;t make fun of me. Of all the holdups, <em>blogging</em> has been the greatest hindrance (it takes me a couple of hours to write about a task that takes 3 &#8211; 5 minutes to accomplish), but blogging has also been the most beneficial restraint that I&#8217;ve imposed on myself&#8211;an even more beneficial restraint than the ol&#8217; unit tests. And, as far as I&#8217;m concerned, the public documentation (and the public support/critique) is well-worth the holdup. So, it&#8217;s been a <em>learning experience</em>, and I want to keep learning. So, the blogging shall continue.</p>
<p>Anyways, I want to apologize for the quasi-failure (if you knew me better, you would&#8217;ve seen it coming), and I pray that, if you&#8217;re reading this series <em>after</em> I&#8217;ve completed writing it, you&#8217;ll still be able to create <em>your</em> website in a month&#8211;as a benefit of my slower process of meandering and divulging. </p>
<p>As a thank you for following along, I&#8217;m going to post the project on Codeplex sometime in the next couple of days. If the speed of my blogging is holding you up, you can download the project, look at the changes I&#8217;ve made, and be on your merry way. For those of you that are okay with the slower pace, never fear; I&#8217;ll keep chugging along in blog form. Until my arms fall off. And my legs. And until every last one of you is sick of my mouthwatering <a href="http://steve-yegge.blogspot.com/">Yegge-like</a> chops. Mmm.</p>
<p>Alright. Enough banter. Today is special. Why, you ask? Because, today, we&#8217;re going to tie up a <em>bunch</em> of loose ends. And, when those loose ends are, eh, so unloose it hurts, we&#8217;ll finally be able to experience an uber-desired form post. That&#8217;s right. A successful form post. It will be a truly fist-pump-worthy event in our otherwise banal and lonely lives.</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/753.jpg"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/753-e1279712422281.jpg" alt="753 e1279712422281 The Big Boy MVC Series    Part 25, Going Postal: ActionFilters, Moq, ModelState, Oh My!" title="753" width="380" height="270" class="alignright size-full wp-image-483" /></a></p>
<p>Let&#8217;s start with an homage to Kazi Manzur&#8217;s <a href="http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx">List of MVC Best Practices</a>. Before you read any further in this post, I recommend that you read Kazi&#8217;s recommendations. While reading, you&#8217;ll notice that Kazi recommends that you implement the PRG pattern (something I blogged about <a href="http://www.weirdlover.com/2010/06/27/the-big-boy-mvc-series-part-21-controller-meet-repo-repo-meet-controller/">here</a>). In laymen&#8217;s terms: when the user posts data, we&#8217;ll verify the data. If the data sucks (no Food Name, no Restaurant Name, bad Address that we can&#8217;t successfully geolocate), we&#8217;ll redirect right back to the <strong>FoodAdd</strong> page, and we&#8217;ll tell the user what he did wrong. If the data doesn&#8217;t suck, we&#8217;ll redirect to the <strong>FoodAdded</strong> page, and we&#8217;ll thank the user for <em>not</em> sucking.</p>
<p>We have one hurdle when we&#8217;re implementing the PRG pattern: when the user sucks, we&#8217;re going to redirect back to the FoodAdd page. When we redirect, MVC is going to destroy any/all of our ModelState errors. But, in this case, we need to preserve those precious ModelState errors because we&#8217;ll use those errors to show the user exactly why and how he sucks. So, in essence, ModelState is our mirror; our user is a fat ugly delusional mess, and we need to do the legwork to plop that mirror right in front of our fat, ugly user&#8217;s mess-of-a face.</p>
<p>Here&#8217;s where Kazi comes in. To pass our ModelState from one request to another, we&#8217;ll create two <a href="http://msdn.microsoft.com/en-us/library/dd410209(VS.90).aspx">ActionFilters</a>. The first attribute, called <strong>PassState</strong>, will insert our ModelStateDictionary into TempData. The second attribute, called <strong>GetState</strong>, will retrieve our ModelStateDictionary from TempData. If you&#8217;re new to ActionFilters, you might want to check out <a href="http://msdn.microsoft.com/en-us/library/dd381609.aspx">this msdn article</a> before diving into deeper waters.</p>
<p>Here&#8217;s our <strong>PassState</strong> ActionFilter. Notice that we&#8217;re adding ModelState to TempData when our ModelState is invalid. This type of scenario is exactly why TempData exists: we can use it to pass data to an action when we redirect (Craig Stuntz goes so far as to call TempData &#8220;<a href="http://blogs.teamb.com/craigstuntz/2009/01/23/37947/">RedirectData</a>&#8221; for this very reason). If you&#8217;re using TempData for any purpose other than <em>passing</em> data right before you redirect, you&#8217;re probably better off using <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.viewpage.viewdata.aspx">ViewData</a>. That said, here&#8217;s our <strong>PassState</strong> ActionFilter, which uses TempData appropriately:</p>
<pre>
<code class="csharp">
using System.Web.Mvc;

namespace Big.Fat.Dish.Controllers.ActionFilters
{
    public class PassStateAttribute : ActionFilterAttribute
    {
        public const string TempDataTransferKey = "__Big.Fat.Dish.TempDataTransferKey";

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            //Only export when ModelState is not valid
            if (!filterContext.Controller.ViewData.ModelState.IsValid)
            {
                //Export if we are redirecting
                if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
                {
                    filterContext.Controller.TempData[TempDataTransferKey] = filterContext.Controller.ViewData.ModelState;
                }
            }

            base.OnActionExecuted(filterContext);
        }
    }
}
</code>
</pre>
<p>And here&#8217;s our <strong>GetState</strong> ActionFilter. We&#8217;re grabbing the <strong>ModelState</strong> object that we lodged into TempData, and we&#8217;re merging it with the current request&#8217;s <strong>ModelState</strong>. Here goes nothing:</p>
<pre>
<code class="csharp">
using System.Web.Mvc;

namespace Big.Fat.Dish.Controllers.ActionFilters
{
    public class GetStateAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            string key = PassStateAttribute.TempDataTransferKey;
            ModelStateDictionary modelState = filterContext.Controller.TempData[key] as ModelStateDictionary;

            if (modelState != null)
            {
                //Only Import if we are viewing
                if (filterContext.Result is ViewResult)
                {
                    filterContext.Controller.ViewData.ModelState.Merge(modelState);
                }
                else
                {
                    //Otherwise remove it.
                    filterContext.Controller.TempData.Remove(key);
                }
            }

            base.OnActionExecuted(filterContext);
        }
    }
}
</code>
</pre>
<p>So, we stole this code from someone else. But that doesn&#8217;t mean that we shouldn&#8217;t test it. As you might imagine, testing ActionFilters can be a little tricky, because you have to mock out a bunch of classes that contain the word &#8220;Context&#8221; in their cozy little class names. As you&#8217;ll surely come to realize (if you haven&#8217;t already), &#8220;Context&#8221; is an MS keyword for &#8220;We&#8217;re doing some crazy unmockable shit in this hizzy!&#8221; Unfortunately, it&#8217;s these very &#8220;Context&#8221; hizzies that we really <em>should</em> mock up, because we&#8217;re way more likely to do something really stupid when we play with them.</p>
<p>Up to this point, I&#8217;ve been using <a href="http://www.ayende.com/projects/rhino-mocks.aspx">RhinoMocks</a> to mock out my objects. To be honest, I used RhinoMocks because I wanted to try it out. I don&#8217;t mind RhinoMocks, but, the reality remains: I&#8217;m an avid Moq fan. I love Moq like I love the ladies (and the Legos). And I&#8217;d be doing you a real disservice if I didn&#8217;t at least introduce you to Moq&#8217;s vibratory Mockgasms.</p>
<p>If you&#8217;ve never worked with Moq, you can read the QuickStart guide <a href="http://code.google.com/p/moq/wiki/QuickStart">here</a>. Once you&#8217;ve digested the basics, I suggest that you head over to <a href="http://stackoverflow.com/questions/970198/how-to-mock-the-request-on-controller-in-asp-net-mvc">StackOverflow</a> and read some of the Moq-related posts there. Once you get the hang of it, I think you&#8217;ll enjoy Moq&#8217;s terser syntax. I think you&#8217;ll also notice that Moq is just as powerful as RhinoMocks, if not more so, especially when it comes to giving you undeniable and pleasurable mockgasms (did I already try that joke?).</p>
<p>So, let&#8217;s setup a couple tests to verify that Kazi&#8217;s ActionFilters are going to work properly in our project. (Never doubt Kazi; you might be struck by a heavy flash of Jesus-steered lightning). To begin, let&#8217;s go ahead and test <strong>PassState</strong>:</p>
<pre>
<code class="csharp">
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Big.Fat.Dish.Controllers.ActionFilters;
using Big.Fat.Dish.Controllers;

namespace Big.Fat.Dish.Tests.Controllers.ActionFilters
{
    [TestClass]
    public class PassStateTest
    {
        PassStateAttribute passState;
        FoodController controller;
        Mock&lt;ActionExecutedContext> actionContext;

        [TestInitialize]
        public void TestInitialize()
        {
            actionContext = new Mock&lt;ActionExecutedContext>();
            passState = new PassStateAttribute();
            controller = new FoodController();

            actionContext.Setup(m => m.Controller).Returns(controller);
        }

        [TestMethod]
        public void Controllers_ActionFilters_PassState_Inserts_ModelState_Into_TempData_If_ModelState_Is_Invalid_And_Result_Is_Redirect()
        {
            controller.ModelState.AddModelError("anyString", "anyError");
            actionContext.Object.Result = new RedirectResult("/");
            passState.OnActionExecuted(actionContext.Object);

            Assert.IsTrue(controller.TempData.ContainsKey(PassStateAttribute.TempDataTransferKey));
            Assert.AreEqual(controller.ModelState, controller.TempData[PassStateAttribute.TempDataTransferKey]);
        }

        [TestMethod]
        public void Controllers_ActionFilters_PassState_Does_Not_Insert_ModelState_Into_TempData_If_ModelState_Is_Invalid_And_Result_Is_Not_Redirect()
        {
            controller.ModelState.AddModelError("anyString", "anyError");
            actionContext.Object.Result = new ViewResult();
            passState.OnActionExecuted(actionContext.Object);

            Assert.IsFalse(controller.TempData.ContainsKey(PassStateAttribute.TempDataTransferKey));
        }

        [TestMethod]
        public void Controllers_ActionFilters_PassState_Does_Not_Insert_ModelState_Into_TempData_If_ModelState_Is_Valid()
        {
            actionContext.Object.Result = new RedirectResult("/");
            passState.OnActionExecuted(actionContext.Object);

            Assert.IsFalse(controller.TempData.ContainsKey(PassStateAttribute.TempDataTransferKey));
        }
    }
}
</code>
</pre>
<p>And, similarly, let&#8217;s test <strong>GetState</strong>:</p>
<pre>
<code class="csharp">
using System.Web.Mvc;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Big.Fat.Dish.Controllers;
using Big.Fat.Dish.Controllers.ActionFilters;

namespace Big.Fat.Dish.Tests.Controllers.ActionFilters
{
    [TestClass]
    public class GetStateTest
    {
        GetStateAttribute getState;
        FoodController controller;
        Mock&lt;ActionExecutedContext> actionContext;
        ModelStateDictionary passedDictionary;

        [TestInitialize]
        public void TestInitialize()
        {
            getState = new GetStateAttribute();
            controller = new FoodController();
            actionContext = new Mock&lt;ActionExecutedContext>();
            passedDictionary = new ModelStateDictionary();
            passedDictionary.AddModelError("anyError", "anyMessage");

            actionContext.Setup(m => m.Controller).Returns(controller);
        }

        [TestMethod]
        public void Controllers_ActionFilters_GetState_Merges_ModelState_If_Result_Is_ViewResult_And_TempData_Contains_Key()
        {
            actionContext.Object.Result = new ViewResult();
            controller.TempData[PassStateAttribute.TempDataTransferKey] = passedDictionary;
            getState.OnActionExecuted(actionContext.Object);

            Assert.IsTrue(controller.ModelState.ContainsKey("anyError"));
        }

        [TestMethod]
        public void Controllers_ActionFilters_GetState_Does_Not_Merge_ModelState_If_Result_Is_Not_ViewResult()
        {
            actionContext.Object.Result = new RedirectResult("/");
            controller.TempData[PassStateAttribute.TempDataTransferKey] = passedDictionary;
            getState.OnActionExecuted(actionContext.Object);

            Assert.IsFalse(controller.ModelState.ContainsKey("anyError"));
        }

        [TestMethod]
        public void Controllers_ActionFilters_GetState_Does_Not_Merge_ModelState_If_TempData_Does_Not_Contain_Key()
        {
            actionContext.Object.Result = new ViewResult();
            getState.OnActionExecuted(actionContext.Object);

            Assert.IsFalse(controller.ModelState.ContainsKey("anyError"));
        }
    }
}
</code>
</pre>
<p>Now that we have our ActionFilters built and tested, we can move on (or return yet again) to our <strong>FoodController</strong>. Since we last visited our FoodController, we&#8217;ve done more than our fair share of work. For starters, we created the ViewModel layer (and mapped our ViewModel to our Model via AutoMapper). We also created a Geocoder, a Permalink generator, and, more recently, we created two ActionFilters (remember?). Let&#8217;s tie it all together:</p>
<pre>
<code class="csharp">
using System;
using System.Web.Mvc;
using Big.Fat.Dish.Models;
using Big.Fat.Dish.ViewModels;
using Big.Fat.Dish.WebRequests.Geocoding;
using Big.Fat.Dish.Controllers.ActionFilters;

namespace Big.Fat.Dish.Controllers
{
    public class FoodController : Controller
    {
        IGeocoder lazyGeocoder;
        IGeocoder geocoder
        {
            get
            {
                if (lazyGeocoder == null)
                {
                    lazyGeocoder = new Geocoder();
                }

                return lazyGeocoder;
            }
        }

        IRepository lazyRepo;
        IRepository repo
        {
            get
            {
                if (lazyRepo == null)
                {
                    lazyRepo = new Repository();
                }

                return lazyRepo;
            }
        }

        public FoodController() : this(null, null) { }
        public FoodController(IRepository repo, IGeocoder geocoder)
        {
            this.lazyRepo = repo;
            this.lazyGeocoder = geocoder;
        }

        [HttpGet, GetState]
        public ViewResult Add()
        {
            return View("Add");
        }

        [HttpPost, PassState]
        public ActionResult Add(FoodAdd form)
        {
            if (!ModelState.IsValid)
            {
                return RedirectToAction("Add");
            }

            Food food = form.Map();
            food.Restaurant.Address = geocoder.GetAddressFromString(form.OneLineAddress);

            if (food.Restaurant.Address == null)
            {
                ModelState.AddModelError("OneLineAddress", "You provided an invalid Restaurant Address.");
                return RedirectToAction("Add");
            }

            this.repo.Foods.CreatePermalinksFor(food);
            this.repo.Add(food);
            this.repo.Save();

            return RedirectToAction("Added", new { id = food.Id });
        }

        public ViewResult Added(int id)
        {
            var model = new FoodAdded
            {
                Food = this.repo.Foods.WithId(id)
            };

            return View(model);
        }

        public ViewResult Details(int id)
        {
            var model = new FoodDetails
            {
                Food = this.repo.Foods.WithId(id)
            };

            return View(model);
        }
    }
}
</code>
</pre>
<p>So, let&#8217;s take a minute to reflect.  When a user posts data in our food form, that data will get bound (via MVC&#8217;s <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.defaultmodelbinder.aspx">DefaultModelBinder</a>). If the user did anything stupid, we&#8217;ll redirect him back to the FoodAdd page (with ModelState errors intact). If the user didn&#8217;t screw anything up, we go ahead and geocode his OneLineAddress. If the geocoder can&#8217;t create an address, we&#8217;ll redirect the user back to the FoodAdd page (with a OneLineAddress error). If the geocoder successfully creates an address, we generate permalinks for all of our records (Food, Address, Restaurant), and we save our food in our good ol&#8217; fashioned database.</p>
<p>You&#8217;ll notice that I&#8217;m not <em>showing you everything</em> here. For example, I created a ViewModel class for each of my ViewPages (FoodAdd, FoodAdded, FoodDetails, and HomeIndex). And I also extended my <strong>Foods</strong> pipe with the CreatePermalinks() method. And, prior to <em>anything</em> else, I created some more coveted unit tests for the new functionality. Since I&#8217;ve completed all of these tasks before (in some fashion or another), I&#8217;m hoping that you can take the initiative to do some work on your side of tracks, thus allowing me to conserve some of my &#8220;precious keystrokes&#8221;.</p>
<h2>Extra Credit</h2>
<p>If you&#8217;re a visual learner, I don&#8217;t blame you. Let&#8217;s take a look at the monster we&#8217;ve created. For starters, set a stopping point in your <strong>post</strong> method. It doesn&#8217;t matter where, really:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/Stopping-Point.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/Stopping-Point-e1279709511256.png" alt="Stopping Point e1279709511256 The Big Boy MVC Series    Part 25, Going Postal: ActionFilters, Moq, ModelState, Oh My!" title="Stopping Point" width="700" height="415" class="alignleft size-full wp-image-472" /></a></p>
<p>Start your project, and navigate to the &#8220;/Food/Add&#8221; page. Add some data into the form. Here&#8217;s my attempt at being user-like with my QAing:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/food-names.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/food-names-e1279709790945.png" alt="food names e1279709790945 The Big Boy MVC Series    Part 25, Going Postal: ActionFilters, Moq, ModelState, Oh My!" title="food names" width="700" height="415" class="alignleft size-full wp-image-474" /></a></p>
<p>Hit the huge-ass Add Food button. Your <strong>post</strong> method should get invoked, so your project should pause at the breaking point. So, VS should look (and feel) something like this:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/breakpoint.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/breakpoint-e1279710005168.png" alt="breakpoint e1279710005168 The Big Boy MVC Series    Part 25, Going Postal: ActionFilters, Moq, ModelState, Oh My!" title="breakpoint" width="700" height="416" class="alignleft size-full wp-image-475" /></a></p>
<p>Take a look at the FoodAdd parameter. You&#8217;ll notice that the data I posted has been property populated (i.e. &#8220;bound&#8221;) into my FoodAdd class:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/Food-Has-Names-Binding.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/Food-Has-Names-Binding-e1279710270252.png" alt="Food Has Names Binding e1279710270252 The Big Boy MVC Series    Part 25, Going Postal: ActionFilters, Moq, ModelState, Oh My!" title="Food Has Names Binding" width="700" height="415" class="alignleft size-full wp-image-476" /></a></p>
<p>Now, let&#8217;s check out the Map() method, which should convert our FoodAdd ViewModel into a Food class. Lo and behold, it does exactly what we had hoped and dreamed!</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/Food-Map-AutoMapper.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/Food-Map-AutoMapper-e1279710967563.png" alt="Food Map AutoMapper e1279710967563 The Big Boy MVC Series    Part 25, Going Postal: ActionFilters, Moq, ModelState, Oh My!" title="Food Map AutoMapper" width="700" height="415" class="alignleft size-full wp-image-477" /></a></p>
<p>Now, the geocoder. I gave the geocoder a really crappy address to resolve, so I was hoping that we&#8217;d get a ModelState error. But, life is funny. And it looks like our geocoder is trying a little too hard to impress us. So, we get an Address returned to us after all (something we&#8217;ll definitely want to tweak at a later date [an easy fix]). Hey, at least we know that the geocoder is <em>working</em>, which is good:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/geocoder.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/geocoder-e1279710686925.png" alt="geocoder e1279710686925 The Big Boy MVC Series    Part 25, Going Postal: ActionFilters, Moq, ModelState, Oh My!" title="geocoder" width="700" height="415" class="alignleft size-full wp-image-478" /></a></p>
<p>The post succeeds, and we&#8217;re transported to the <strong>FoodAdded</strong> page. I&#8217;ve spruced this page up just a little bit, so don&#8217;t be afraid. Also notice that I&#8217;m still tinkering with the verbiage:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/add-another-dish.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/add-another-dish-e1279710835792.png" alt="add another dish e1279710835792 The Big Boy MVC Series    Part 25, Going Postal: ActionFilters, Moq, ModelState, Oh My!" title="add another dish" width="700" height="416" class="alignleft size-full wp-image-479" /></a></p>
<p>Now, to top it all off, take a look in your database. Everything should be fine and dandy:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/query.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/query-e1279711560516.png" alt="query e1279711560516 The Big Boy MVC Series    Part 25, Going Postal: ActionFilters, Moq, ModelState, Oh My!" title="query" width="700" height="336" class="alignleft size-full wp-image-480" /></a></p>
<p>Cool. So we have one successful (although unintentional) post under our belts. Let&#8217;s navigate back to the &#8220;/Add/Food&#8221; page and submit a blank form. Again, our project is paused at the breaking point. If you fish around, you&#8217;ll notice that ModelState is <em>not</em> valid. Then, you&#8217;ll notice that ModelState contains three errors. Then, if you do some serious digging, you&#8217;ll find the error messages that ModelState has created for us:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/ModelStateErrors.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/ModelStateErrors-e1279711750228.png" alt="ModelStateErrors e1279711750228 The Big Boy MVC Series    Part 25, Going Postal: ActionFilters, Moq, ModelState, Oh My!" title="ModelStateErrors" width="700" height="415" class="alignleft size-full wp-image-481" /></a></p>
<p>Now it&#8217;s time for our <a href="http://www.weirdlover.com/2010/07/15/the-big-boy-mvc-series-part-24-dear-editortemplates-are-we-done-posting-yet/">EditorTemplate</a> to do its magic. The user is redirected to the  FoodAdd page, which now displays all of the ModelState error messages (thanks to our PassStateAttribute, GetStateAttribute, and EditorTemplate):</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/error-messages.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/error-messages-e1279712010695.png" alt="error messages e1279712010695 The Big Boy MVC Series    Part 25, Going Postal: ActionFilters, Moq, ModelState, Oh My!" title="error messages" width="700" height="381" class="alignleft size-full wp-image-482" /></a></p>
<hr/>
<p>Good times. More good times are surely ahead of us.</p>
<p>Move on to <a href="http://www.weirdlover.com/2010/08/19/big-boy-mvc-part-26-its-codeplex-time/">Part 26: <strong>It&#8217;s Codeplex Time!</strong></a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.weirdlover.com/2010/07/21/the-big-boy-mvc-series-part-25-going-postal-actionfilters-moq-modelstate-oh-my/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Chirpy Attains Godlike Bird-Power In Version 1.0.0.4</title>
		<link>http://www.weirdlover.com/2010/07/18/chirpy-attains-godlike-abilities-in-version-1-0-0-4/</link>
		<comments>http://www.weirdlover.com/2010/07/18/chirpy-attains-godlike-abilities-in-version-1-0-0-4/#comments</comments>
		<pubDate>Sun, 18 Jul 2010 01:27:59 +0000</pubDate>
		<dc:creator>Evan</dc:creator>
				<category><![CDATA[ASP.NET MVC]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<category><![CDATA[Chirpy]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Zippy]]></category>

		<guid isPermaLink="false">http://www.weirdlover.com/?p=449</guid>
		<description><![CDATA[Let's start with the simplest part: <a href="http://chirpy.codeplex.com/">download Chirpy at codeplex</a>. Start fiddling around. If something doesn't work <a href="http://chirpy.codeplex.com/workitem/list/basic">complain about it</a>. If something does work, tweet or blog about how awesome your <a href="http://twitter.com/weirdmvc">life has become</a>. Finally, if you're feeling really frisky, download Chirpy's source code and add something. I don't care what it is. Just add something. Surprise me. I'll probably love you forever. Or, I'll throw something at you.]]></description>
			<content:encoded><![CDATA[<p>Hopefully, you&#8217;re a fan of hyperbole.</p>
<p>If you&#8217;re new to Chirpy, or if you need a refresher, or if you&#8217;re interested in learning about the new Chirpy functionality, this post is for you. I&#8217;m lifting my glass. I hope that you&#8217;re lifting yours, too.</p>
<p>Let&#8217;s start with the simplest part: <a href="http://chirpy.codeplex.com/">download Chirpy at codeplex</a>. Start fiddling around. If something doesn&#8217;t work <a href="http://chirpy.codeplex.com/workitem/list/basic">complain about it</a>. If something does work, tweet or blog about how awesome your <a href="http://twitter.com/weirdmvc">life has become</a>. Finally, if you&#8217;re feeling really frisky, download Chirpy&#8217;s source code and add something. I don&#8217;t care what it is. Just add something. Surprise me. I&#8217;ll probably love you forever. Or, I&#8217;ll throw something at you.</p>
<hr/>
<p>Speaking of contributors. I&#8217;d like to tip my hat to the main Chirpy contributors: Please send them money and flowers: <a href="http://blog.waynebrantley.com/">Wayne Brantley</a>, <a href="http://www.codeplex.com/site/users/view/ploufs">Francis Noel (aka <em>ploufs</em>)</a>, and <a href="http://andy.edinborough.org/">Andy Edinborough</a>. I owe them all a huge thank you. And many beers. And hugs.</p>
<hr />
<p>This page contains everything (new and old) that you&#8217;d ever need to know about Chirpy. For all intents and purposes, you can navigate to the section that interests you most, follow the quasi-steps, and be on your merry way. Or, if you&#8217;re a sucker for pain, you can sludge through the entire document. Whatever makes you happiest. In sum, with Chirpy, you can:</p>
<ul>
<li><a href="#minify-js">&#8230;minify javascript files</a></li>
<li><a href="#dotless">&#8230;translate DotLess files into css files</a></li>
<li><a href="#minify-css">&#8230;minify css files</a></li>
<li><a href="#mash">&#8230;mash content files together</a></li>
<li><a href="#validate">&#8230;validate javascript and DotLess files</a></li>
<li><a href="#autorun">&#8230;autorun T4 templates (incl. T4MVC)</a></li>
</ul>
<hr />
<h3 id="minify-js">Benefit 1: Minify the Crap Out of Your Javascript Files</h3>
<p>Step 1: <strong>Install Chirpy</strong>. The latest version of Chirpy can be downloaded at <a href="http://chirpy.codeplex.com/">Codeplex</a>.</p>
<p>Step 2: <strong>Add a javascript file to your project.</strong> Name the file &#8220;woo.yui.js&#8221;. Adding the â€œ.yui.jsâ€ suffix to our filename is Chirpyâ€™s cue to look after the file. Right away, youâ€™ll notice that Chirpy has adorned our new javascript file with a â€œcodebehindâ€ file:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/woo-yui-js-e1279410033962.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/woo-yui-js-e1279410033962.png" alt="woo yui js e1279410033962 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="woo yui js" width="700" height="415" class="alignnone size-full wp-image-450" /></a></p>
<p>Step 3: <strong>Type some javascript in the woo.yui.js file</strong>. Save your changes, and check out the codebehind file. Chirpy has created a minified version of your file (using YUI Compressor). Here&#8217;s my unminified file:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/unminified-js.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/unminified-js-e1279410277142.png" alt="unminified js e1279410277142 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="unminified js" width="700" height="415" class="alignnone size-full wp-image-451" /></a></p>
<p>And here&#8217;s the codebehind file, which Chirpy generated for me:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/js-codebehind.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/js-codebehind-e1279410357232.png" alt="js codebehind e1279410357232 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="js codebehind" width="700" height="416" class="alignnone size-full wp-image-452" /></a></p>
<p>Step 4: <strong>Use a different compressor</strong>. If you don&#8217;t like the YUI Compressor, that&#8217;s okay. Chirpy can also minify your file using Google Closure Tools. Currently, Chirpy will handle five different javascript extensions:</p>
<ul>
<li><strong>file.yui.js</strong> &#8211; uses YUI Compressor to minify your file</li>
<li><strong>file.whitespace.js</strong> &#8211; uses Google Closure Tools to remove all of the extra spaces from your file</li>
<li><strong>file.simple.js</strong> &#8211; uses Google Closure Tools to minify your javascript file (with simple optimizations)</li>
<li><strong>file.gct.js</strong> &#8211; uses Google Closure Tools to minify your javascript file (with advanced optimizations)</li>
<li><strong>file.chirp.js</strong> &#8211; Chirpy picks the best minifier for the job, and minifies your javascript file accordingly</li>
</ul>
<p>So, let&#8217;s go ahead and change <strong>woo.yui.js</strong> to <strong>woo.whitespace.js</strong>. Here&#8217;s the new codebehind file:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/whitespace-codebehind.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/whitespace-codebehind-e1279410846868.png" alt="whitespace codebehind e1279410846868 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="whitespace codebehind" width="700" height="415" class="alignnone size-full wp-image-453" /></a></p>
<p>Step 5: <strong>Still not happy? Change the extension names</strong>. If you don&#8217;t like the extensions that Chirpy uses to manhandle files, click <strong>Tools >> Options >> Chirpy</strong>. Here, you can change the  file extensions to whatever suits your fancy. For demoing purposes, I&#8217;ll change &#8220;.whitespace.js&#8221; to &#8220;.w.js&#8221;:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/Options-Screen.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/Options-Screen-e1279410993301.png" alt="Options Screen e1279410993301 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="Options Screen" width="700" height="416" class="alignnone size-full wp-image-454" /></a></p>
<p>Now, when I change my &#8220;woo.whitespace.js&#8221; file to &#8220;woo.w.js&#8221;, Chirpy still performs its magic:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/woo-w.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/woo-w-e1279411071882.png" alt="woo w e1279411071882 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="woo w" width="700" height="416" class="alignnone size-full wp-image-455" /></a></p>
<hr/>
<h3 id="dotless">Benefit 2: Translate DotLess Files.</h3>
<p>Step 1: <strong>Install Chirpy</strong>. The latest version of Chirpy can be downloaded at <a href="http://chirpy.codeplex.com/">Codeplex</a>.</p>
<p>Step 2: <strong>Add a DotLess file to your project.</strong>. Name the file &#8220;woo.chirp.less&#8221;. Adding the â€œ.chirp.lessâ€ suffix to our filename is Chirpyâ€™s cue to look after the file. Right away, youâ€™ll notice that Chirpy has adorned our new DotLess file with two (that&#8217;s right, count &#8216;em, two) â€œcodebehindâ€ files:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/woo-chirp-less.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/woo-chirp-less-e1279411573284.png" alt="woo chirp less e1279411573284 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="woo chirp less" width="700" height="416" class="alignnone size-full wp-image-456" /></a></p>
<p>Step 3: <strong>Add DotLess crap to our DotLess file.</strong>. If you&#8217;re new to DotLess, check out the <a href="http://www.dotlesscss.com/">documentation</a>. Here&#8217;s a little taste of the DRYer-than-css DotLess syntax:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/less-crap1.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/less-crap1-e1279412856169.png" alt="less crap1 e1279412856169 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="less crap" width="700" height="416" class="alignnone size-full wp-image-463" /></a></p>
<p>Chirpy translates this DotLess craziness into valid css. The unminified version of the css can be found in the &#8220;woo.css&#8221; file:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/woo-css.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/woo-css-e1279412888138.png" alt="woo css e1279412888138 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="woo css" width="700" height="415" class="alignnone size-full wp-image-458" /></a></p>
<p>And the minified version of the css can be found in the &#8220;woo.min.css&#8221; file:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/woo-min-css1.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/woo-min-css1-e1279412921283.png" alt="woo min css1 e1279412921283 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="woo min css" width="700" height="415" class="alignnone size-full wp-image-464" /></a></p>
<p>Step 4: <strong>Change the file&#8217;s extension</strong>. Like the javascript extensions, you can change the &#8220;.chirp.less&#8221; extension to whatever you like by fiddling with the configuration settings in the <strong>Tools >> Options >> Chirpy</strong> menu. By default, even without changing any of Chirpy&#8217;s configuration settings, Chirpy will convert files with the &#8220;.chirp.less&#8221; and the &#8220;.chirp.less.css&#8221; extensions.</p>
<hr/>
<h3 id="minify-css">Benefit 3: Minify the crap out of CSS Files.</h3>
<p>Step 1: <strong>Install Chirpy</strong>. The latest version of Chirpy can be downloaded at <a href="http://chirpy.codeplex.com/">Codeplex</a>.</p>
<p>Step 2: <strong>Add a css file to your project.</strong>. Name the file &#8220;coo.chirp.css&#8221;. Adding the â€œ.chirp.cssâ€ suffix to our filename is Chirpyâ€™s cue to look after the file. Right away, youâ€™ll notice that Chirpy has adorned our new css file with a â€œcodebehindâ€ file:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/coo-chirp.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/coo-chirp-e1279412464357.png" alt="coo chirp e1279412464357 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="coo chirp" width="700" height="415" class="alignnone size-full wp-image-460" /></a></p>
<p>Step 3: <strong>Write some css in your chirp.css file</strong>. The codebehind file will contain a minified version of your madness.</p>
<p>Here&#8217;s my unminified css file:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/coo-chirp-code.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/coo-chirp-code-e1279412675719.png" alt="coo chirp code e1279412675719 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="coo chirp code" width="700" height="416" class="alignnone size-full wp-image-461" /></a></p>
<p>And here&#8217;s the minified css file that Chirpy autogenerated for me:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/coo-min-css.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/coo-min-css-e1279413192642.png" alt="coo min css e1279413192642 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="coo min css" width="700" height="416" class="alignnone size-full wp-image-462" /></a></p>
<hr/>
<h3 id="mash">Benefit 4: Mash files together.</h3>
<p>Step 1: <strong>Install Chirpy</strong>. The latest version of Chirpy can be downloaded at <a href="http://chirpy.codeplex.com/">Codeplex</a>.</p>
<p>Step 2: <strong>Add a config file to your project.</strong>. Name the file &#8220;mash.chirp.config&#8221;. Adding the â€œ.chirp.configâ€ suffix to our filename is Chirpyâ€™s cue to look after the file.</p>
<p>Step 3: <strong>Specify what files you want to mash together</strong>. Here&#8217;s the syntax:</p>
<pre>
<code class="html">
&lt;root>
    &lt;FileGroup Name="group1.js">
        &lt;File Path="jquery-1.4.1.min.js" Minify="false" />
        &lt;File Path="jquery.json.js" />
        &lt;File Path="MicrosoftAjax.js" />
    &lt;/FileGroup>

    &lt;FileGroup Name="group2.js">
        &lt;File Path="jquery-1.4.1.min.js" Minify="false" />
        &lt;File Path="jquery.json.js" />
    &lt;/FileGroup>

    &lt;FileGroup Name="group1.css">
        &lt;File Path="../Styles/jquery-ui-1.8.custom.css" />
        &lt;File Path="../Styles/colorbox.css" />
        &lt;File Path="howdy.chirp.less" />
    &lt;/FileGroup>
&lt;/root>
</code>
</pre>
<p>Step 4: <strong>Save the config file</strong>. As a result, three codebehind files will be created:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/05/mash.chirp_.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/05/mash.chirp_.png" alt="mash.chirp  Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="mash.chirp" width="278" height="116" class="size-full wp-image-133" /></a><br />
<br/></p>
<p>Step 5: <strong>Add folders to your config file (if you&#8217;d like)</strong>. If you have a folder full of files that you&#8217;d like to mash together, you don&#8217;t have to list out each file. Instead, you can do something like this:</p>
<pre>
<code class="html">
&lt;root>
    &lt;FileGroup Name="main.scripts.js">
        &lt;Folder Path="/" Type="*.min.js" Minify="false"/>
        &lt;File Path="MicrosoftAjax.js" />
    &lt;/FileGroup>
&lt;/root>
</code>
</pre>
<hr/>
<h3 id="validate">Benefit 5: Validate Javascript and DotLess files</h3>
<p>Step 1: <strong>Screw up some of your coveted javascript</strong>. Assuming that you followed the steps for creating a <strong>yui.js</strong> file, go ahead and add some stupid code into your file. Maybe, eh, something stupidly awesome like this:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/invalid-js.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/invalid-js-e1279413916998.png" alt="invalid js e1279413916998 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="invalid js" width="700" height="415" class="alignnone size-full wp-image-465" /></a></p>
<p>Step 2: <strong>Save your screw-up</strong>. Upon saving, you&#8217;ll notice a pleasantly annoying error message:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/woo-js-error.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/woo-js-error-e1279414184667.png" alt="woo js error e1279414184667 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="woo js error" width="700" height="416" class="alignnone size-full wp-image-466" /></a></p>
<p>Step 3: <strong>Screw up some css in your DotLess file</strong>. Upon saving, you&#8217;ll receive yet another annoyingly friendly error message:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/css-error.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/css-error-e1279414285215.png" alt="css error e1279414285215 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="css error" width="700" height="417" class="alignnone size-full wp-image-467" /></a></p>
<hr/>
<h3 id="autorun">Benefit 6: Autorun T4 Templates</h3>
<p>Step 1: <strong>Install Chirpy</strong>. The latest version of Chirpy can be downloaded at <a href="http://chirpy.codeplex.com/">Codeplex</a>.</p>
<p>Step 2: In Visual Studio, go to <strong>Tools >> Options >> Chirpy</strong>. You can tell Chirpy to auto-update T4 templates whenever you build your project:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/t4-gen.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/t4-gen-e1279414620137.png" alt="t4 gen e1279414620137 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="t4 gen" width="700" height="417" class="alignnone size-full wp-image-468" /></a></p>
<p>Step 3: <strong>Get to know T4MVC.</strong> Granted, this feature may feel a wee bit out of place. But there&#8217;s a special place in my heart (and Wayne Brantley&#8217;s heart) for David Ebbo&#8217;s labor-of-love, <a href="http://mvccontrib.codeplex.com/">T4MVC</a>.  So, Chirpy can auto-update T4MVC when you make a change to a pertinent MVC file (as discussed by Wayne <a href="http://blog.waynebrantley.com/2010/03/t4mvc-add-in-to-auto-run-template.html">here</a>). To smart-run the T4MVC template, just make sure that the <strong>Smart Run T4MVC</strong> checkbox is checked:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/smart-run-t4mvc.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/smart-run-t4mvc-e1279414884577.png" alt="smart run t4mvc e1279414884577 Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="smart run t4mvc" width="700" height="415" class="alignnone size-full wp-image-469" /></a></p>
<hr/>
<p>That&#8217;s it! Chirpy says: <strong>Happy Coding!</strong></p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/05/Zippy.jpg"><img src="http://www.weirdlover.com/wp-content/uploads/2010/05/Zippy.jpg" alt="Zippy Chirpy Attains Godlike Bird Power In Version 1.0.0.4" title="Zippy" width="355" height="451" class="aligncenter size-full wp-image-64" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.weirdlover.com/2010/07/18/chirpy-attains-godlike-abilities-in-version-1-0-0-4/feed/</wfw:commentRss>
		<slash:comments>43</slash:comments>
		</item>
		<item>
		<title>The Big Boy MVC Series &#8212; Part 24: Dear EditorTemplates, Are We Done Posting Yet?</title>
		<link>http://www.weirdlover.com/2010/07/15/the-big-boy-mvc-series-part-24-dear-editortemplates-are-we-done-posting-yet/</link>
		<comments>http://www.weirdlover.com/2010/07/15/the-big-boy-mvc-series-part-24-dear-editortemplates-are-we-done-posting-yet/#comments</comments>
		<pubDate>Thu, 15 Jul 2010 04:47:08 +0000</pubDate>
		<dc:creator>Evan</dc:creator>
				<category><![CDATA[Big Boy MVC]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Big Boy]]></category>
		<category><![CDATA[EditorTemplates]]></category>
		<category><![CDATA[MVC]]></category>

		<guid isPermaLink="false">http://www.weirdlover.com/?p=441</guid>
		<description><![CDATA[When we talk about "improving" our skills as knowledge-hungry developers, I find it interesting that we rarely mention the people in our lives (not Karl Seguin, alas) who we inevitably and repeatedly injure with our sloppiness: namely, <em>designers</em>. Yes, <em>those people</em>, over there, cloaked in Urban Outfitter attire, crying, listening to Bon Iver (or, like, whatever).]]></description>
			<content:encoded><![CDATA[<p>New to <strong>The Big Boy MVC Series</strong>?<br />
Read the series from its <a href="http://www.weirdlover.com/2010/05/29/the-big-boy-mvc-series-building-an-asp-net-mvc-web-application-all-by-yourself-part-1/"><strong>humble beginnings</strong></a>.</p>
<hr/>
<p>In a <a href="http://codebetter.com/blogs/karlseguin/archive/2010/01/14/you-should-know-linux.aspx">somewhat elderly article</a>, Karl Seguin suggests that all programmers should know Linux. And C. And memory management. And pointers. Karl stops just short of requesting that you cease making love to other people. But, if abstinence helps you become pseudo (homonymical pun intended) good at Linux, well then so be it. Stop making love. That&#8217;s why I stopped making love, in fact. Not because the demand for my love-making skills plummeted. But because I wanted to <em>learn</em>.</p>
<p>When we talk about &#8220;improving&#8221; our skills as knowledge-hungry developers, I find it interesting that we rarely mention the people in our lives (not Karl Seguin, alas) who we inevitably and repeatedly injure with our sloppiness: namely, <em>designers</em>. Yes, <em>those people</em>, over there, cloaked in Urban Outfitter attire, crying, listening to Bon Iver (or, like, whatever). We&#8217;re responsible for 90% of their personal anguish, and yet, when it comes time to improving ouselves, we dive deeper and deeper into the black subhuman vortex of pure, unadulterated, unstyled nerdiness, all while ignoring the needs and desires of our poor (though good-looking and well-dressed) designer. It&#8217;s time to change that.</p>
<p>Today, we&#8217;re going to make eye-contact. We&#8217;re going to <em>try</em> to feel the pain of the designer. We&#8217;re going to hug. And, in the end, we&#8217;re going to harness the power of MVC to make the life of our designer (or, in this case, the lives of ourselves) as easy as possible. </p>
<p>Step 1: <strong>Create an EditorTemplate folder</strong>. Place this folder in the <strong>Views/Shared</strong> subfolder. A.K.A.:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/editor-template-folder-e1279163634698.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/editor-template-folder-e1279163634698.png" alt="editor template folder e1279163634698 The Big Boy MVC Series    Part 24: Dear EditorTemplates, Are We Done Posting Yet?" title="editor template folder" width="700" height="416" class="alignleft size-full wp-image-443" /></a></p>
<p>Step 2: <strong>Avoid touching others. Learn more about EditorTemplates before doing something ill advised</strong>. There are two <em>amazingly</em> helpful resources that you should devour before continuing here. First, read Brad Wilson&#8217;s multi-post series about MVC templates <a href="http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html">here</a>. Second, read Elijah Manor&#8217;s post about opinionated template helpers <a href="http://elijahmanor.com/webdevdotnet/post/Opinionated-ASPNET-MVC-2-Template-Helpers.aspx">here</a>. That should get you better acquainted with the technical aspects of our magical journey. </p>
<p>Step 3: <strong>Create a design-friendly EditorTemplate</strong>. As mindblowingly awesome as Brad and Elijah&#8217;s proclamations are, I encountered some real trouble when I started to style the rendered output.  I decided that each of my EditorTemplates should double as a design module. That way, when I want to change the look and feel of a form, I can swap out one EditorTemplate for another. Hopefully, as we go along, you&#8217;ll begin to see why this approach will make the design process a bit more manageable for us.</p>
<p>For starters, we&#8217;ll place the following code into a MVC partial, and we&#8217;ll save it as <strong>Grid3-6.ascx</strong>. Place <strong>Grid3-6.ascx</strong> into the newly created <strong>EditorTemplates</strong> folder. Simple enough. If you read Elijah&#8217;s post, you&#8217;ll notice that I stole a sizable chunk of this code from his helpful code snippet:</p>
<pre>
<code class="html">
&lt;%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>

&lt;div class="template">
&lt;% if (ViewData.TemplateInfo.TemplateDepth > 1) { %>
    &lt;%-- outlet for a shallow dive in a deep pool --%>
    &lt;%= ViewData.ModelMetadata.SimpleDisplayText %>
&lt;%
    } else {
        var data = ViewData.ModelMetadata;
        var template = ViewData.TemplateInfo;
        var properties = data.Properties.Where(m => m.ShowForEdit &#038;&#038; !template.Visited(m));
%>
    &lt;% foreach (var property in properties) { %>
        &lt;% if (property.HideSurroundingHtml) { %>
            &lt;%-- no label, no validation message, no skirt --%>
            &lt;%= Html.Editor(property.PropertyName) %>
        &lt;% } else { %>
            &lt;div class="field">
                &lt;span class="label grid-3">
                    &lt;label for="&lt;%: property.PropertyName %>">&lt;%: property.DisplayName %>:&lt;/label>
                    &lt;span class="req &lt;%: property.IsRequired? "visible" : "invisible" %>">*&lt;/span>
                &lt;/span>

                &lt;span class="input grid-6">
                    &lt;%: Html.Editor(property.PropertyName) %>
                &lt;/span>

                &lt;% if (!ViewData.ModelState.IsValidField(property.PropertyName)) { %>
                    &lt;span class="validation grid-6 prefix-3">
                            &lt;span class="error icon">&lt;/span>
                            &lt;%: Html.ValidationMessage(property.PropertyName) %>
                    &lt;/span>
                &lt;% } %>
            &lt;/div>
        &lt;% } %>
    &lt;% } %>
&lt;% } %>
&lt;/div>
</code>
</pre>
<p>Notice that we&#8217;re taking advantage of our <a href="http://www.weirdlover.com/2010/06/09/the-big-boy-mvc-series-%E2%80%94-part-9-creating-page-prototypes/">960 grid system</a>. For starters, our label will be 3 grid-lengths long, and the wrapper around our input field will be 6 grid-lengths long. Below the label and the input field, we&#8217;ll display a validation error message (if it exists). That validation message should be left-aligned with our input field. Also, as an added (though possibly unnecessary touch), required fields will be marked with a visible red asterisk. Unrequired fields will also be marked with a red asterisk, but those asterisks will be set to <strong>visibility:hidden</strong>, thus maintaining easy alignment.</p>
<p>Step 4: <strong>Update the FoodAdd page</strong>. If you&#8217;ve been following along, we&#8217;ve already done a considerable amount of work on our <a href="http://www.weirdlover.com/2010/06/20/the-big-boy-mvc-series-part-17-curing-a-moderately-bad-case-of-divitis/">FoodAdd page</a>. Time now for another quick, painless iteration:</p>
<pre>
<code class="html">
&lt;%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage&lt;FoodAdd>" %> 

&lt;asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
    Big Fat Dish - Add a New Food
&lt;/asp:Content> 

&lt;asp:Content ID="Content3" ContentPlaceHolderID="MainContent" runat="server">
    &lt;div class="container-16 wrap">
        &lt;div class="block">
            &lt;h1>Add a New Food to Big Fat Dish&lt;/h1>

            &lt;% Html.BeginForm(); %>
                &lt;div id="add-image" class="grid-4">
                    &lt;div id="image-input" class="new">Click to Add an Image&lt;/div>
                &lt;/div> 

                &lt;%: Html.EditorForModel("Grid3-6") %>               

                &lt;div id="add-food" class="grid-14 submit">
                    &lt;input type="submit" value="Add Food" />
                &lt;/div>
            &lt;% Html.EndForm(); %>
        &lt;/div>
    &lt;/div>
&lt;/asp:Content>
</code>
</pre>
<p>Step 5: <strong>Style your EditorTemplate</strong>. If the process of styling your EditorTemplate isn&#8217;t easy, or if the resulting styles aren&#8217;t reusable, you should consider reworking your EditorTemplate. For the sake of your designer. Because the goal here is to make the design process as easy and as modularized as possible. Because your designer is sensitive. And the EditorTemplate should be his friend.</p>
<p>To style my EditorTemplate, I downloaded the overly extensive <a href="http://speckyboy.com/2008/07/28/96-best-ever-free-icon-sets-for-web-designers-developers-and-bloggers/">Fugue Icon Set</a>. I also did some peripheral styling. I added some fades, some borders, some margins, and some much-need padding. You know, <em>designer stuff</em>. All in all, you can tell that I&#8217;m a bit of a fanboy of the <a href="http://themeforest.net/collections/231353-the-envato-technique">Envato Technique</a>:</p>
<pre>
<code class="css">
/* generic */
html, body
{
	background-color:#2c2a29;
	font-family: Helvetica, Geneva;
}

.hide
{
	display:none;
}

.invisible
{
	visibility:hidden;
}

ul.no-list li
{
	list-style-type:none;
}

.no-decor
{
	text-decoration:none;
}

/* containers */
.container-16.wrap
{
	border:1px solid #bbb;
	overflow:hidden;
}

.block
{
	border:1px solid #fff;
	overflow:hidden;
	background-color:#f6f6f6;
	padding:40px 0px 20px 60px;
}

/* frame */
#header, #navigation, #content, #footer-top, #footer-bottom
{
	overflow:hidden;
}

#header, #navigation, #footer-top, #footer-bottom
{
	color:#86806b;
}

#header a, #navigation a, #footer-top a, #footer-bottom a
{
	color:#cdc0a9;
	text-decoration:none;
}

#header
{
	height:60px;
	padding:5px 0px 10px 0px;
	background:#3b3b3b url("images/fades/fade_3b3b3b_1x199.png") repeat-x;
}

#navigation
{
	background:#4a4439 url("images/fades/fade_4a4439_1x32.png") repeat-x top left;
}

#navigation ul li
{
	padding-top:17px;
	border-left:1px solid #5e5749;
	height:33px;
	text-align:center;
	margin:4px 0px 2px 0px;
}

#navigation ul li.last /* last nav tab */
{
	border-right:1px solid #5e5749;
}

#content
{
	padding:40px 0px 50px 0px;
	background:#d2d1cf url("images/fades/fade_d2d1cf_1x190.png") repeat-x top left;
	border-bottom:1px solid #efefef;
}

#footer-top
{
	height:200px;
	background:#3b3630;
	border-top:1px solid #010000;
	border-bottom:1px solid #4e4a44;
}

#footer-bottom
{
	background:#2c2a28;
}

#footer-bottom
{
	padding-top:10px;
	height:60px;
	border-top:1px solid #232220;
	font-size:11px;
}

/* form elements */
.field
{
	overflow:hidden;
	margin-bottom:10px;
}

.field input, .field .label
{
	font-size:16px;
}

.field input
{
	/* TODO: handle checkboxes, etc */
	width:100%;
	border:1px solid #ccc;
}

.field .label
{
	text-align:right;
}

.field .req
{
	color:#aa2c2c;
}

.field .validation
{
	margin-top:5px;
	font-size:13px;
	color:#aa2c2c;
}

.field-validation-error
{
	display:block;
	float:left;
}

.icon
{
	margin-right:10px;
	display:block;
	float:left;
	width:16px;
	height:16px;
}

.error.icon
{
	background:transparent url("images/icons/fugue/exclamation-red.png") no-repeat;
}

.submit
{
	height:70px;
	margin:40px 10px 10px 10px;
}

.submit input
{
	height:100%;
	width:100%;
}

.button, .submit input
{
	border:none;
	text-align:center;
	background:#ea6e4c;
	color:#fff;
	font-size:35px;
	cursor:pointer;
	padding:10px 0px;

	-moz-border-radius: 5px;
	-webkit-border-radius: 5px;
}

/* home index */
#foods
{
	float:left;
	margin-top:10px;
}

#add-food
{
	margin:40px 10px 30px 10px;
}

/* add food */
#image-input
{
	text-align:center;
	font-size:16px;
	background:#efefef;
	width:100%;
	height:180px;
}

#image-input.new
{
	padding-top:20px;
	border:1px solid #ccc;
}
</code>
</pre>
<p>Step 6: <strong>Test out your designer-friendly template</strong>. Make sure that it looks acceptable in all of the standard browsers (I tend to care less about Internet Explorer&#8217;s feelings). Once you&#8217;ve done that, you can bask in the glory of all of your hard, hard work:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/EditorTemplate-Designed.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/EditorTemplate-Designed-e1279167912422.png" alt="EditorTemplate Designed e1279167912422 The Big Boy MVC Series    Part 24: Dear EditorTemplates, Are We Done Posting Yet?" title="EditorTemplate Designed" width="700" height="416" class="alignleft size-full wp-image-445" /></a></p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/Errors.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/Errors-e1279167971101.png" alt="Errors e1279167971101 The Big Boy MVC Series    Part 24: Dear EditorTemplates, Are We Done Posting Yet?" title="Errors" width="700" height="417" class="alignleft size-full wp-image-446" /></a></p>
<p>My design could surely still use a <em>real designer&#8217;s</em> touch. But, when that touch finally comes, it should be a swift and painless one. Like chocolate-coated dreams. </p>
<p>At the very least, our newly created, quasi-modularized design is definitely an improvement over our original page style (if I don&#8217;t say so myself):</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/06/add-food2.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/06/add-food2-e1276906659229.png" alt="add food2 e1276906659229 The Big Boy MVC Series    Part 24: Dear EditorTemplates, Are We Done Posting Yet?" title="add food" width="700" height="379" class="alignnone size-full wp-image-359" style="border:1px solid #666" /></a></p>
<hr/>
<p>Now, with a little bit of elbow grease, we can easily create as many EditorTemplates as we desire. </p>
<p>But, first, it might not be a bad idea to buy your favorite designer some tropical flowers. Or a copy of <a href="http://www.objectifiedfilm.com/">Objectified</a>. Or, that movie about <a href="http://www.helveticafilm.com/">Helvetica</a>. Or, a firm manly hug. Or, a letter. Or, a copy of Linux for Designers.</p>
<hr/>
<p>Move on to <a href="http://www.weirdlover.com/2010/07/21/the-big-boy-mvc-series-part-25-going-postal-actionfilters-moq-modelstate-oh-my/">The Big Boy MVC Series &#8212; <strong>Part 25, Going Postal: ActionFilters, Moq, ModelState, Oh My!</strong></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.weirdlover.com/2010/07/15/the-big-boy-mvc-series-part-24-dear-editortemplates-are-we-done-posting-yet/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>The Big Boy MVC Series &#8212; Part 23: Baby Got Postbacks, a Preamble</title>
		<link>http://www.weirdlover.com/2010/07/09/the-big-boy-mvc-series-part-23-baby-got-postbacks-a-preamble/</link>
		<comments>http://www.weirdlover.com/2010/07/09/the-big-boy-mvc-series-part-23-baby-got-postbacks-a-preamble/#comments</comments>
		<pubDate>Fri, 09 Jul 2010 10:45:45 +0000</pubDate>
		<dc:creator>Evan</dc:creator>
				<category><![CDATA[Big Boy MVC]]></category>
		<category><![CDATA[Big Boy]]></category>
		<category><![CDATA[Geocoding]]></category>
		<category><![CDATA[Permalinks]]></category>

		<guid isPermaLink="false">http://www.weirdlover.com/?p=434</guid>
		<description><![CDATA[Whoo. It's been awhile. Apologies for that. I've been looking for a new place to live in Honolulu, and the whole process has been an uphill battle (thanks for asking). It appears that real estate brokers don't like it too much when you fill in the "<strong>Sex: ___________</strong>" blank with "<strong><u>OFFENDER</u></strong>"]]></description>
			<content:encoded><![CDATA[<p>New to <strong>The Big Boy MVC Series</strong>?<br />
Read the series from its <a href="http://www.weirdlover.com/2010/05/29/the-big-boy-mvc-series-building-an-asp-net-mvc-web-application-all-by-yourself-part-1/"><strong>humble beginnings</strong></a>.</p>
<hr/>
<p>Whoo. It&#8217;s been awhile. Apologies for that. I&#8217;ve been looking for a new place to live in Honolulu, and the whole process has turned out to be an uphill battle (thanks for asking). It appears that real estate brokers don&#8217;t really like it too much when you fill in the &#8220;<strong>Sex: ___________</strong>&#8221; blank with &#8220;<strong><u>OFFENDER</u></strong>&#8220;. </p>
<p>Some of you might have died between Part 22 and Part 23. That&#8217;s okay. For those of you who are still sentient and coherent and death-free, you&#8217;ll remember that, in Part 22, we set up our ViewModel layer, and we mapped our <strong>FoodAdd</strong> ViewModel to our Model <strong>Food</strong> class (which was autogenerated by Linq 2 SQL). Remember? If not, go ahead and take a stroll down <a href="http://www.weirdlover.com/2010/07/01/the-big-boy-mvc-series-part-22-whoop/">memory lane</a>.</p>
<p>Today, we&#8217;re going to handle our first Http Post. Since, like cheese, you&#8217;ve  aged (and learned some stuff) as we&#8217;ve trekked along on this journey of ours, I&#8217;m going to provide <em>more code</em> and less banter in this post. Or, maybe not.</p>
<p>Step 1: <strong>Make some small changes to your dbml file and your database</strong>. I destroyed the <strong>States</strong> table, I cleaned up the column names, I added permalink columns to each table, and I added a <strong>Points</strong> table. These small changes will help us keep our downstream code so fresh and so clean. Also, if you&#8217;re skillfully building your application, these minor tweaks should be super easy to implement. If they&#8217;re not, you&#8217;re probably suffering from a good ol&#8217; case of <a href="http://en.wikipedia.org/wiki/Spaghetti_code">spaghetti fever</a>. Lasagna:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/BFD.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/BFD-e1278652165473.png" alt="BFD e1278652165473 The Big Boy MVC Series    Part 23: Baby Got Postbacks, a Preamble" title="BFD" width="700" height="416" class="alignnone size-full wp-image-436" /></a></p>
<p>Step 2: <strong>Design a permalink generator</strong>. All the cool kids are doing it. And, like a cool kid, we want to be able to feed our permalink generator a stupid string like &#8220;Hub&#8217;s Hot Dog H3X##~~0rFest&#8221;, and, in turn, we want our permalink generator to spit out a clean url-friendly string like &#8220;hubs-hot-dog-h3x0rfest&#8221;. Easy enough, eh? Heck, if it&#8217;s <em>that</em> easy maybe you should try to create this permalink generator <em>all by your big-boy self</em>, eh? Your version might suck much less than mine. And, if it does, please e-mail it to me. Or, if it doesn&#8217;t, feel free to steal mine.</p>
<p>Already finished? Well, okay then. Let&#8217;s compare biceps. </p>
<p>Here are my unit tests:</p>
<pre>
<code class="csharp">
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Big.Fat.Dish.Models;

namespace Big.Fat.Dish.Tests.Models
{
    [TestClass]
    public class PermalinkTest
    {
        [TestMethod]
        public void Models_Permalink_For_Trims_Spaces()
        {
            string title = "    hello-there     ";
            string permalink = Permalink.For(title);
            Assert.AreEqual("hello-there", permalink);
        }

        [TestMethod]
        public void Models_Permalink_For_Delimits()
        {
            string title = "here is my title";
            string permalink = Permalink.For(title);
            Assert.AreEqual("here-is-my-title", permalink);
        }

        [TestMethod]
        public void Models_Permalink_For_Converts_To_LowerInvariant()
        {
            string title = "HeRe";
            string permalink = Permalink.For(title);
            Assert.AreEqual("here", permalink);
        }

        [TestMethod]
        public void Models_Permalink_For_Trims_Inner()
        {
            string title = "here  is    my      title";
            string permalink = Permalink.For(title);
            Assert.AreEqual("here-is-my-title", permalink);
        }

        [TestMethod]
        public void Models_Permalink_For_Removes_NonAlphanumeric_Chars()
        {
            string title = "Mr. Jim Lives in Room 1,209----ok?";
            string permalink = Permalink.For(title);
            Assert.AreEqual("mr-jim-lives-in-room-1209-ok", permalink);
        }

        [TestMethod, ExpectedException(typeof(ArgumentNullException))]
        public void Models_Permalink_For_Throws_Null_Argument_Error_When_Null()
        {
            string error = Permalink.For(null);
        }

        [TestMethod, ExpectedException(typeof(ArgumentNullException))]
        public void Models_Permalink_For_Throws_Null_Argument_Error_When_Empty()
        {
            string error = Permalink.For(string.Empty);
        }

        [TestMethod]
        public void Models_Permalink_For_Generates_Permalinks_For_NonalphaNames()
        {
            string name = Permalink.For("###", ifEmptyUse:"permalink");

            Assert.IsNotNull(name);
            Assert.AreEqual(name, "permalink");
        }
    }
}
</code>
</pre>
<p>And here is my <strong>Permalink Generator</strong>:</p>
<pre>
<code class="csharp">
using System;
using System.Text.RegularExpressions;

namespace Big.Fat.Dish.Models
{
    public static class Permalink
    {
        static Regex nonAlphanumeric = new Regex(@"[^\w\d\s\-]+", RegexOptions.Compiled);
        static Regex spacesAndDashes = new Regex(@"[\s\-]+", RegexOptions.Compiled);

        public static string For(string value, string delimiter = "-", string ifEmptyUse = "#")
        {
            if (string.IsNullOrEmpty(value))
            {
                throw new ArgumentNullException("value");
            }

            string alpha = nonAlphanumeric.Replace(value, string.Empty).Trim().ToLowerInvariant();
            string delimitedAlpha = spacesAndDashes.Replace(alpha, delimiter);

            if (string.IsNullOrWhiteSpace(delimitedAlpha))
            {
                return ifEmptyUse;
            }
            else
            {
                return delimitedAlpha;
            }
        }
    }
}
</code>
</pre>
<p>Step 3: <strong>Design a server-side geocoder</strong>. A whaaaa? </p>
<p>This is a bit trickier. In fact, this might be the &#8220;trickiest&#8221; piece of code that we&#8217;ve written thus far, or that we&#8217;ll ever write in this measly little pea-brained application of ours. Hence, to accomplish this feat of strange brilliance, you&#8217;ll need to have a basic understanding of <a href="http://msdn.microsoft.com/en-us/library/bb410770.aspx">JSON Serialization</a>. And you&#8217;ll also need to get pretty cozy with the <a href="http://code.google.com/apis/maps/index.html">Google Maps API</a>. So, get cracking.</p>
<p>We&#8217;re going to make a <strong>WebRequest</strong> to Google. When we make our web request, we&#8217;re proverbially asking Google if we can come over, chat about soccer, and make sweet sweet love on the beige ottoman. e.g.:</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/Dolphin-Mating-Ritual-1.jpg"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/Dolphin-Mating-Ritual-1.jpg" alt="Dolphin Mating Ritual 1 The Big Boy MVC Series    Part 23: Baby Got Postbacks, a Preamble" title="Dolphin-Mating-Ritual (1)" width="500" height="335" class="alignnone size-full wp-image-437" /></a></p>
<p>I should stop here for a second and disclose an important legal disclaimer: since we&#8217;re grabbing and parsing geocoding data from grandfather Google, we can only use that data for Google Mapping purposes. And, as the <a href="http://groups.google.com/group/google-maps-api/browse_thread/thread/ce5b4ededca3486b">TOS explicitly states</a>, we&#8217;re legally obliged to regularly update this data such that the data, at any given point, is &#8220;temporary&#8221;. That should hopefully keep our project on the borderline of &#8220;non-prostitutory&#8221; and &#8220;legit&#8221;&#8211;and, thus, with any luck, we won&#8217;t find ourselves embroiled in a David/Goliath battle with the ol&#8217; internet giant. If we do, we can always run. Like a girl. Or, we can just go ahead and start using <a href="http://www.bing.com/maps/">Bing Maps</a>.</p>
<p>Like always, let&#8217;s start with some unit tests. When building our geocoding unit tests, we need to make sure that we <em>don&#8217;t</em> make a real WebRequest. Google (long wind, sleeping giant) wouldn&#8217;t like that. So, instead, we&#8217;ll use <strong>RhinoMocks</strong> to mock out a fake WebRequest, which we&#8217;ll use to return a (fake) serializied JSON string that our geocoder can fiddle with. </p>
<pre>
<code class="csharp">
using System.IO;
using System.Web.Script.Serialization;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
using Big.Fat.Dish.Models;

namespace Big.Fat.Dish.Tests.WebRequests.Geocoding
{
    [TestClass]
    public class GeocoderTest
    {
        MockRepository mocks;
        IGeocoder geocoder;
        IWebRequestWrap request;
        JavaScriptSerializer serializer;

        const string anyString = "pointless";
        GeoAddress deserializedAddress = new GeoAddress
        {
            Status = new Status
            {
                Code = GeoResponse.Success,
                Request = "geocode"
            },
            Placemark = new Placemark[]
            {
                new Placemark
                {
                    AddressDetails = new AddressDetails
                    {
                        Country = new Country
                        {
                            AdministrativeArea = new AdministrativeArea
                            {
                                AdministrativeAreaName = "WA",
                                SubAdministrativeArea = new SubAdministrativeArea
                                {
                                    Locality = new Locality
                                    {
                                        LocalityName = "Seattle",
                                        Thoroughfare = new Thoroughfare
                                        {
                                            ThoroughfareName = "111 Seattle WA 98116"
                                        },
                                        PostalCode = new PostalCode
                                        {
                                            PostalCodeNumber = "98116"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    Point = new GeoPoint
                    {
                        Coordinates = new float[]
                        {
                            100,
                            -100
                        }
                    }
                }
            }
        };

        [TestInitialize]
        public void Init()
        {
            mocks = new MockRepository();
            request = mocks.DynamicMock&lt;IWebRequestWrap>();
            serializer = new JavaScriptSerializer();

            string serializedAddress = serializer.Serialize(deserializedAddress);
            request.Stub(m => m.GetResponseAsString(Arg&lt;string>.Is.Anything)).Return(serializedAddress);

            geocoder = new Geocoder(request);
            mocks.ReplayAll();
        }

        [TestCleanup]
        public void TestCleanup()
        {
            mocks.VerifyAll();
        }

        [TestMethod]
        public void WebRequests_Geocoder_GetAddressFromString_Returns_Line1()
        {
            Address returnedAddress = geocoder.GetAddressFromString(anyString);
            Assert.AreEqual("111 Seattle WA 98116", returnedAddress.Line1);
        }

        [TestMethod]
        public void WebRequests_Geocoder_GetAddressFromString_Line2_Is_Null()
        {
            Address returnedAddress = geocoder.GetAddressFromString(anyString);
            Assert.IsNull(returnedAddress.Line2);
        }

        [TestMethod]
        public void WebRequests_Geocoder_GetAddressFromString_Returns_City()
        {
            Address returnedAddress = geocoder.GetAddressFromString(anyString);
            Assert.AreEqual("Seattle", returnedAddress.City);
        }

        [TestMethod]
        public void WebRequests_Geocoder_GetAddressFromString_Returns_State()
        {
            Address returnedAddress = geocoder.GetAddressFromString(anyString);
            Assert.AreEqual("WA", returnedAddress.State);
        }

        [TestMethod]
        public void WebRequests_Geocoder_GetAddressFromString_Returns_PostalCode()
        {
            Address returnedAddress = geocoder.GetAddressFromString(anyString);
            Assert.AreEqual("98116", returnedAddress.PostalCode);
        }

        [TestMethod]
        public void WebRequests_Geocoder_GetAddressFromString_Returns_Point_Longitude()
        {
            Address returnedAddress = geocoder.GetAddressFromString(anyString);
            Assert.AreEqual(100, returnedAddress.Point.Longitude);
        }

        [TestMethod]
        public void WebRequests_Geocoder_GetAddressFromString_Returns_Point_Lattitude()
        {
            Address returnedAddress = geocoder.GetAddressFromString(anyString);
            Assert.AreEqual(-100, returnedAddress.Point.Latitude);
        }

        [TestMethod]
        public void WebRequests_Geocoder_GetAddressFromString_Returns_Null_On_Error()
        {
            deserializedAddress.Status.Code = GeoResponse.BadKey;
            Init();

            Address returnedAddress = geocoder.GetAddressFromString(anyString);
            Assert.IsNull(returnedAddress);
        }
    }
}
</code>
</pre>
<p>Alrighty. Let&#8217;s start building! First, we need to create a wrapper for our WebRequest. In a similar flash of passion, we spent some time a few days ago <a href="http://www.weirdlover.com/2010/06/22/the-big-boy-mvc-series-part-19-linq-to-sql-wrap-up-that-datacontext-buddy/">wrapping up our frisky DataContext</a>. For now, with our <strong>WebRequestWrap class</strong>, we really only need to expose one method. He&#8217;s a lonely fellow:</p>
<pre>
<code class="csharp">
namespace Big.Fat.Dish.WebRequests
{
    public interface IWebRequestWrap
    {
        string GetResponseAsString(string uri);
    }
}
</code>
</pre>
<p>And our implementation:</p>
<pre>
<code class="csharp">
using System.Net;
using System.IO;

namespace Big.Fat.Dish.WebRequests
{
    public class WebRequestWrap : IWebRequestWrap
    {
        public string GetResponseAsString(string uri)
        {
            var request = WebRequest.Create(uri);
            var response = request.GetResponse();
            string responseAsString;

            using (var stream = response.GetResponseStream())
            using (var reader = new StreamReader(stream))
            {
                responseAsString = reader.ReadToEnd();
            }

            return responseAsString;
        }
    }
}
</code>
</pre>
<p>Next, let&#8217;s create our <strong>Geocoder</strong> class. Here&#8217;s the interface:</p>
<pre>
<code class="csharp">
using Big.Fat.Dish.WebRequests.Geocoding.Deserialized;
using Big.Fat.Dish.Models;

namespace Big.Fat.Dish.WebRequests.Geocoding
{
    public interface IGeocoder
    {
        Address GetAddressFromString(string address);
    }
}
</code>
</pre>
<p>And the <strong>Geocoder</strong> class:</p>
<pre>
<code class="csharp">
using System.Web.Script.Serialization;
using Big.Fat.Dish.WebRequests.Geocoding.Deserialized;
using Big.Fat.Dish.WebRequests;
using Big.Fat.Dish.Models;

namespace Big.Fat.Dish.WebRequests.Geocoding
{
    public class Geocoder : IGeocoder
    {
        const string MapKey = "GetYourOwnMapKey,Buddy";
        const string MapUrl = "http://maps.google.com/maps/geo?q={0}&#038;output=json&#038;oe=utf8&#038;sensor=false&#038;key={1}";

        IWebRequestWrap webRequest;

        public Geocoder() : this(new WebRequestWrap()) { }
        public Geocoder(IWebRequestWrap webRequest)
        {
            this.webRequest = webRequest;
        }

        GeoAddress Geocode(string streetAddress)
        {
            //handle null address
            if (string.IsNullOrEmpty(streetAddress)) return null;

            //get json response
            string url = string.Format(MapUrl, streetAddress, MapKey);
            string response = webRequest.GetResponseAsString(url);

            //serialize response
            try
            {
                var serializer = new JavaScriptSerializer();
                var jsonAddress = serializer.Deserialize<GeoAddress>(response);

                return jsonAddress;
            }
            catch
            {
                return null;
            }
        }

        public Address GetAddressFromString(string streetAddress)
        {
            var geo = Geocode(streetAddress);
            if (geo == null || geo.Status == null || geo.Status.Code != GeoResponse.Success)
            {
                return null;
            }

            try
            {
                var placemark = geo.Placemark[0];
                var adminArea = placemark.AddressDetails.Country.AdministrativeArea;
                var locality = adminArea.SubAdministrativeArea.Locality;
                var coords = placemark.Point.Coordinates;

                return new Address
                {
                    Line1 = locality.Thoroughfare.ThoroughfareName,
                    Line2 = null,
                    City = locality.LocalityName,
                    State = adminArea.AdministrativeAreaName,
                    PostalCode = locality.PostalCode.PostalCodeNumber,
                    Point = new Point
                    {
                        Longitude = coords[0],
                        Latitude = coords[1]
                    }
                };
            }
            catch
            {
                return null;
            }
        }
    }
}
</code>
</pre>
<p>The only missing piece of this big, bad puzzle: the <strong>GeoAddress</strong> class (&#038; crap), which our deserializer fills to the brim with spicy geocoding data. I&#8217;ve included all of the classes below, so hopefully you get the idea. Don&#8217;t blame me for the class-count here; blame Google:</p>
<blockquote>
<h4>GeoAddress</h4>
<pre>
<code class="csharp">
namespace Big.Fat.Dish.WebRequests.Geocoding.Deserialized
{
    public class GeoAddress
    {
        public Placemark[] Placemark { get; set; }
        public Status Status { get; set; }
    }
}
</code>
</pre>
<h4>Placemark</h4>
<pre>
<code class="csharp">
namespace Big.Fat.Dish.WebRequests.Geocoding.Deserialized
{
    public class Placemark
    {
        public GeoPoint Point { get; set; }
        public AddressDetails AddressDetails { get; set; }
    }
}
</code>
</pre>
<h4>Status</h4>
<pre>
<code class="csharp">
namespace Big.Fat.Dish.WebRequests.Geocoding.Deserialized
{
    public class Status
    {
        public GeoResponse Code { get; set; }
        public string Request { get; set; }
    }
}
</code>
</pre>
<h4>GeoPoint</h4>
<pre>
<code class="csharp">
namespace Big.Fat.Dish.WebRequests.Geocoding.Deserialized
{
    public class GeoPoint
    {
        public float[] Coordinates { get; set; }
    }
}
</code>
</pre>
<h4>AddressDetails</h4>
<pre>
<code class="csharp">
namespace Big.Fat.Dish.WebRequests.Geocoding.Deserialized
{
    public class AddressDetails
    {
        public Country Country { get; set; }
    }
}
</code>
</pre>
<h4>Country</h4>
<pre>
<code class="csharp">
namespace Big.Fat.Dish.WebRequests.Geocoding.Deserialized
{
    public class Country
    {
        public AdministrativeArea AdministrativeArea { get; set; }
    }
}
</code>
</pre>
<h4>AdministrativeArea</h4>
<pre>
<code class="csharp">
namespace Big.Fat.Dish.WebRequests.Geocoding.Deserialized
{
    public class AdministrativeArea
    {
        public string AdministrativeAreaName { get; set; }
        public SubAdministrativeArea SubAdministrativeArea { get; set; }
    }
}
</code>
</pre>
<h4>SubAdministrativeArea</h4>
<pre>
<code class="csharp">
namespace Big.Fat.Dish.WebRequests.Geocoding.Deserialized
{
    public class SubAdministrativeArea
    {
        public Locality Locality { get; set; }
    }
}
</code>
</pre>
<h4>Locality</h4>
<pre>
<code class="csharp">
namespace Big.Fat.Dish.WebRequests.Geocoding.Deserialized
{
    public class Locality
    {
        public string LocalityName { get; set; }
        public Thoroughfare Thoroughfare { get; set; }
        public PostalCode PostalCode { get; set; }
    }
}
</code>
</pre>
<h4>Thoroughfare</h4>
<pre>
<code class="csharp">
namespace Big.Fat.Dish.WebRequests.Geocoding.Deserialized
{
    public class Thoroughfare
    {
        public string ThoroughfareName { get; set; }
    }
}
</code>
</pre>
<h4>PostalCode</h4>
<pre>
<code class="csharp">
namespace Big.Fat.Dish.WebRequests.Geocoding.Deserialized
{
    public class PostalCode
    {
        public string PostalCodeNumber { get; set; }
    }
}
</code>
</pre>
<h4>GeoResponse</h4>
<pre>
<code class="csharp">
namespace Big.Fat.Dish.WebRequests.Geocoding.Deserialized
{
    public enum GeoResponse
    {
        Success = 200,
        BadRequest = 400,
        ServerError = 500,
        MissingQuery = 601,
        MissingAddress = 601,
        UnknownAddress = 602 | 604,
        UnavailableAddress = 603,
        BadKey = 610,
        TooManyQueries = 620
    }
}
</code>
</pre>
</blockquote>
<p>Step 4: <strong>Run the tests. Feel the Purple Rain</strong>. Our geocoder works. Our permalink generator works. Our hearts are almost completely mended (you may not realize it yet):</p>
<p><a href="http://www.weirdlover.com/wp-content/uploads/2010/07/Tests-Passed.png"><img src="http://www.weirdlover.com/wp-content/uploads/2010/07/Tests-Passed-e1278672229946.png" alt="Tests Passed e1278672229946 The Big Boy MVC Series    Part 23: Baby Got Postbacks, a Preamble" title="Tests Passed" width="700" height="416" class="alignnone size-full wp-image-438" /></a></p>
<hr/>
<p>Move on to <a href="http://www.weirdlover.com/2010/07/15/the-big-boy-mvc-series-part-24-dear-editortemplates-are-we-done-posting-yet/">Part 24: <strong>Dear EditorTemplates, Are We Done Posting Yet?</strong></a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.weirdlover.com/2010/07/09/the-big-boy-mvc-series-part-23-baby-got-postbacks-a-preamble/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

