<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-9194677942308742051</id><updated>2012-01-26T16:18:24.694-05:00</updated><category term='NUnit'/><category term='chocolatey'/><category term='RequireJS'/><category term='Button'/><category term='Delete'/><category term='Castle'/><category term='Inversion of Control'/><category term='Pound'/><category term='ASP.NET MVC'/><category term='AsyncController'/><category term='Testing'/><category term='Exception handling'/><category term='CruiseControl.NET'/><category term='Model Binding'/><category term='Node.js'/><category term='GitHub'/><category term='NServiceBus'/><category term='TopShelf'/><category term='Agile'/><category term='Follow'/><category term='CancelKeyPress'/><category term='vagrant'/><category term='HTML'/><category term='Patterns'/><category term='MySql'/><category term='JavaScript'/><category term='Unit Testing'/><category term='HTTP methods'/><category term='Automation'/><category term='Put'/><title type='text'>Mike Dellanoce's Blog</title><subtitle type='html'>Talking to Myself</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>21</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-930536025751600495</id><published>2011-12-10T15:45:00.000-05:00</published><updated>2011-12-10T15:46:28.772-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RequireJS'/><category scheme='http://www.blogger.com/atom/ns#' term='Node.js'/><title type='text'>Zero-friction Javascript Minification with RequireJS and Express</title><content type='html'>Most software development efforts involve multiple source code files, and Javascript-heavy web applications are no exception. However, if you want your application to &lt;a href="http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309"&gt;load fast&lt;/a&gt;, then you need to combine and minify all those Javascript files somehow. &lt;a href="http://requirejs.org/"&gt;RequireJS&lt;/a&gt; is a library that can help with this process by allowing you to define javascript modules and the dependencies between them. In "development mode", RequireJS will download modules individually as they are needed. When all of your scripts are shiny and bug-free you can run the optimization tool which will analyze the module dependencies and create a single, minified Javascript file.&lt;br /&gt;&lt;br /&gt;The optimization tool is usually run as part of a build process before deploying the application, but if your application runs on &lt;a href="http://nodejs.org"&gt;Node.js&lt;/a&gt; you can eliminate this extra step. Since the optimization tool is itself a Node.js script, it can be invoked directly from the application's start-up code. Here is what this might look like with the fantastic &lt;a href="http://expressjs.com"&gt;Express web framework&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1453578.js?file=gistfile1.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;In development mode, the application will serve the non-optimized Javascript files from the &lt;i&gt;public&lt;/i&gt; folder. In production mode, the RequireJS optimizer will combine and minify the Javascript files and serve the optimized files from the &lt;i&gt;public_build&lt;/i&gt; folder. Any other files in the &lt;i&gt;public&lt;/i&gt; folder (such as images and stylesheets) will also be copied to the &lt;i&gt;public_build&lt;/i&gt; folder, so you don't need to clutter your source code repository with generated files.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-930536025751600495?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/930536025751600495/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2011/12/zero-friction-javascript-minification.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/930536025751600495'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/930536025751600495'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2011/12/zero-friction-javascript-minification.html' title='Zero-friction Javascript Minification with RequireJS and Express'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-5348402125549678269</id><published>2011-12-04T08:48:00.000-05:00</published><updated>2011-12-04T19:26:43.545-05:00</updated><title type='text'>Commit early, commit often</title><content type='html'>Hidden deep inside &lt;a href="http://tortoisesvn.net/"&gt;TortoiseSVN&lt;/a&gt; is a reporting tool that can give you &lt;a href="http://tortoisesvn.net/docs/release/TortoiseSVN_en/tsvn-dug-showlog.html#tsvn-dug-showlog-5"&gt;statistics about commits to your repository&lt;/a&gt;. I ran this report at my &lt;a href="http://www.rackspace.com/"&gt;day job&lt;/a&gt; several times over the years and the output has always been a quiet source of pride for me. I decided to publish the report here since I'm moving on to a new project. If nothing else, it serves as a reminder to myself of what I spent in the last four years doing:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-A3GkGGSPrJQ/TtvYp_j0_eI/AAAAAAAAAEA/qetxZNbuAMw/s1600/most_active_all_time.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="293" width="400" src="http://1.bp.blogspot.com/-A3GkGGSPrJQ/TtvYp_j0_eI/AAAAAAAAAEA/qetxZNbuAMw/s400/most_active_all_time.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;This is the commit history for the entire four years of the project up to the date when this post was published (names have been removed to protect the innocent). I account for about &lt;b&gt;18% of the total commits&lt;/b&gt; to the repository. One of my teammates (who incidentally owns the third highest bar in the graph) claimed that I average &lt;b&gt;7.5 commits per hour&lt;/b&gt; assuming a 40 hour work week (ha). I think his math might be a little off since I calculated a significantly less impressive 5 commits per day when I ran the numbers... although maybe his numbers are a little closer if you exclude the year I served in management.&lt;br /&gt;&lt;br /&gt;Hold on a second...&lt;br /&gt;&lt;br /&gt;This can't be fair, can it? I've been on the team longer than anyone else at this point, so of course I've amassed more commits. Well, let's look at the commit history for one month during which the team membership was relatively stable:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-fxJ3ejq0Eas/TtvY6wMckNI/AAAAAAAAAEM/SF6QA7sEtnQ/s1600/most_active_february_2011.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="293" width="400" src="http://1.bp.blogspot.com/-fxJ3ejq0Eas/TtvY6wMckNI/AAAAAAAAAEM/SF6QA7sEtnQ/s400/most_active_february_2011.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Me again, and by a wider margin, too.&lt;br /&gt;&lt;br /&gt;A lot of my teammates were shocked as these graphs made their way around the team, but there are benefits to working at this pace:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You are less likely to break something with a lot of small commits than you are with a few huge ones,&lt;/li&gt;&lt;li&gt;Your teammates see your code sooner, so you get feedback sooner and reduce the risk of merge conflicts,&lt;/li&gt;&lt;li&gt;Customers get features and bug fixes sooner (as long as other organizational factors don't stand in the way),&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.codinghorror.com/blog/2008/08/check-in-early-check-in-often.html"&gt;And plenty of other reasons&lt;/a&gt; smarter people have already enumerated.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;For me, writing software is all about momentum. I am more stressed out at the end of the day if I &lt;b&gt;don't&lt;/b&gt; commit a whole bunch of code.&lt;br /&gt;&lt;br /&gt;Happy committing!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-5348402125549678269?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/5348402125549678269/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2011/11/commit-early-commit-often.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/5348402125549678269'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/5348402125549678269'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2011/11/commit-early-commit-often.html' title='Commit early, commit often'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-A3GkGGSPrJQ/TtvYp_j0_eI/AAAAAAAAAEA/qetxZNbuAMw/s72-c/most_active_all_time.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-4355961689954810461</id><published>2011-11-15T06:54:00.001-05:00</published><updated>2011-11-19T14:42:03.417-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Button'/><category scheme='http://www.blogger.com/atom/ns#' term='GitHub'/><category scheme='http://www.blogger.com/atom/ns#' term='Follow'/><title type='text'>Octophile: Social media widgets for GitHub</title><content type='html'>Last week I put one of those &lt;a href="http://twitter.com/about/resources/followbutton"&gt;Twitter follow buttons&lt;/a&gt; on my blog. It was cool, but it looked a little lonely all by itself. It occurred to me that other developers can follow me on &lt;a href="https://github.com"&gt;GitHub&lt;/a&gt; too, so I started looking for a similar button for GitHub. Much to my surprise, I was not able to find one. Luckily, GitHub has &lt;a href="http://developer.github.com/"&gt;a pretty awesome API&lt;/a&gt;, so I decided to try to make a follow button for GitHub myself. I cobbled together a small &lt;a href="http://www.sinatrarb.com/"&gt;sinatra&lt;/a&gt; application, pushed it to &lt;a href="http://www.heroku.com"&gt;heroku&lt;/a&gt;, and &lt;a href="http://octophile.com"&gt;octophile.com&lt;/a&gt; was born!&lt;br /&gt;&lt;br /&gt;You can see the GitHub follow button in action off to the right (if you are reading this on my website and not a RSS reader). If you find this button useful, or would like to see some other widgets like this, I'd love to hear your feedback.&lt;br /&gt;&lt;br /&gt;Happy coding!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update 11/19/2011:&lt;/b&gt;&lt;br /&gt;I have since found that something like this &lt;i&gt;does&lt;/i&gt; already exist: &lt;a href="http://githubanywhere.com/"&gt;github anywhere&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-4355961689954810461?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/4355961689954810461/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2011/11/octophile-social-media-widgets-for.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/4355961689954810461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/4355961689954810461'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2011/11/octophile-social-media-widgets-for.html' title='Octophile: Social media widgets for GitHub'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-6865686963025270433</id><published>2011-10-13T21:37:00.000-04:00</published><updated>2011-11-10T09:31:32.099-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='chocolatey'/><category scheme='http://www.blogger.com/atom/ns#' term='vagrant'/><title type='text'>Easy vagrant setup on windows with chocolatey</title><content type='html'>Setting up &lt;a href="http://vagrantup.com/"&gt;vagrant&lt;/a&gt; on windows is &lt;a href="http://vagrantup.com/docs/getting-started/setup/windows.html"&gt;well-documented&lt;/a&gt; and, overall, pretty easy. However, it is a little more complicated than just:&lt;br /&gt;&lt;pre&gt;gem install vagrant&lt;br /&gt;&lt;/pre&gt;Luckily, us Windows developers recently got &lt;a href="http://chocolatey.org/"&gt;chocolatey&lt;/a&gt;. I just put together a few packages that makes vagrant setup on Windows a snap. To try it out just follow the &lt;a href="http://chocolatey.org/"&gt;chocolatey installation instructions&lt;/a&gt;. Then open a command prompt and run:&lt;br /&gt;&lt;pre&gt;cinst vagrant&lt;br /&gt;&lt;/pre&gt;This command will download and install &lt;a href="http://jruby.org/"&gt;JRuby&lt;/a&gt;, &lt;a href="https://www.virtualbox.org/"&gt;VirtualBox&lt;/a&gt;, &lt;a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/"&gt;PuTTY&lt;/a&gt;, and the vagrant gem. It will also automatically set the registry keys for putty so that once you set up a box with vagrant you can SSH into it with:&lt;br /&gt;&lt;pre&gt;putty -load vagrant&lt;br /&gt;&lt;/pre&gt;At this point the package comes with the old "works on my machine" stamp.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-dubNhXAo5Ag/TpeQ9GvQK0I/AAAAAAAAABc/uNAZX4JLksI/s1600/works-on-my-machine.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="193" src="http://2.bp.blogspot.com/-dubNhXAo5Ag/TpeQ9GvQK0I/AAAAAAAAABc/uNAZX4JLksI/s320/works-on-my-machine.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Check out the code on &lt;a href="https://github.com/mdellanoce/chocolateypackages"&gt;github&lt;/a&gt; or &lt;a href="https://github.com/mdellanoce/chocolateypackages/issues"&gt;report an issue&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update 11/10/2011:&lt;/b&gt;&lt;br /&gt;More recent versions of the package will not modify the putty registry with the vagrant profile. Instead I recommend installing &lt;a href="https://github.com/mdellanoce/vagrant-putty"&gt;vagrant-putty&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-6865686963025270433?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/6865686963025270433/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2011/10/easy-vagrant-setup-on-windows-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/6865686963025270433'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/6865686963025270433'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2011/10/easy-vagrant-setup-on-windows-with.html' title='Easy vagrant setup on windows with chocolatey'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-dubNhXAo5Ag/TpeQ9GvQK0I/AAAAAAAAABc/uNAZX4JLksI/s72-c/works-on-my-machine.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-2067313465648820781</id><published>2011-09-22T09:56:00.000-04:00</published><updated>2011-09-22T09:56:43.464-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HTTP methods'/><category scheme='http://www.blogger.com/atom/ns#' term='Pound'/><category scheme='http://www.blogger.com/atom/ns#' term='Put'/><category scheme='http://www.blogger.com/atom/ns#' term='Delete'/><title type='text'>Enabling Pound proxy support for the HTTP methods PUT and DELETE</title><content type='html'>I'm not sure how many people out there are using&amp;nbsp;&lt;a href="http://www.apsis.ch/pound/"&gt;Pound&lt;/a&gt;&amp;nbsp;as a reverse proxy, but if you have it sitting in front of a ReSTful web service you may run into some issues with HTTP methods other than GET, POST, and HEAD. By default Pound only supports GET, POST, and HEAD. Pound will return an HTTP status code of 501 (not implemented) if it encounters a different method, such as PUT or DELETE.&lt;br /&gt;&lt;br /&gt;Resolving this issue is easy. Each ListenHTTP or ListenHTTPS section in your pound configuration may contain the xHTTP setting. The default value for this setting is 0 (GET, POST, and HEAD). Setting the value to 1 adds support for PUT and DELETE. So putting it all together:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;ListenHTTP&lt;br /&gt;   # ... some settings&lt;br /&gt;   xHTTP 1 #Support GET, POST, HEAD, PUT, and DELETE&lt;br /&gt;   # ... some more settings&lt;br /&gt;End&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Happy proxying!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-2067313465648820781?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/2067313465648820781/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2011/09/enabling-pound-proxy-support-for-http.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/2067313465648820781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/2067313465648820781'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2011/09/enabling-pound-proxy-support-for-http.html' title='Enabling Pound proxy support for the HTTP methods PUT and DELETE'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-2681709272149656736</id><published>2011-08-29T07:19:00.000-04:00</published><updated>2011-08-29T07:19:09.595-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HTML'/><title type='text'>HTML Basics: Labels and inputs</title><content type='html'>I stumbled across some code the other day that made me smile. Here is essentially what was going on:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;input&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="checkbox"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="checkbox"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;label&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="label"&lt;/span&gt; &lt;span class="attr"&gt;for&lt;/span&gt;&lt;span class="kwrd"&gt;="checkbox"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;My Label&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;label&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="text/javascript"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;$(&lt;span class="str"&gt;'#label'&lt;/span&gt;).click(&lt;span class="kwrd"&gt;function&lt;/span&gt;() {&lt;br /&gt;   &lt;span class="kwrd"&gt;var&lt;/span&gt; checkbox = $(&lt;span class="str"&gt;'#checkbox'&lt;/span&gt;);&lt;br /&gt;   checkbox.attr(&lt;span class="str"&gt;'checked'&lt;/span&gt;, !checkbox.&lt;span class="kwrd"&gt;is&lt;/span&gt;(&lt;span class="str"&gt;':checked'&lt;/span&gt;));&lt;br /&gt;});&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;script&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Naturally, this bit of javascript will toggle the checkbox's checked state whenever the label is clicked. There is nothing functionally wrong with this approach, except that it is wasted effort. Every browser I have ever worked with will do this automatically without any javascript. Simply associate a label with a checkbox (or radio button) and clicking the label will toggle the checkbox's checked state:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;input&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="checkbox"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="checkbox"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;label&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="label"&lt;/span&gt; &lt;span class="attr"&gt;for&lt;/span&gt;&lt;span class="kwrd"&gt;="checkbox"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;My Label&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;label&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;input id="checkbox" type="checkbox" /&gt;&lt;label for="checkbox"&gt;Go ahead, click me&lt;/label&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-2681709272149656736?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/2681709272149656736/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2011/08/html-basics-labels-and-inputs.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/2681709272149656736'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/2681709272149656736'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2011/08/html-basics-labels-and-inputs.html' title='HTML Basics: Labels and inputs'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-8284056490965772311</id><published>2011-03-27T09:35:00.000-04:00</published><updated>2011-03-27T09:35:07.567-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MySql'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='NUnit'/><title type='text'>Testing MySQL queries with NUnit</title><content type='html'>Even the most adamant unit-testing purist will admit that database queries need to be tested. If possible, these tests should run against the same database engine that will be used in production.&lt;br /&gt;&lt;br /&gt;With a SQL Server database, testing queries is fairly easy, since most Visual Studio installations will include SQL Server Express. Just create the database in a &lt;a href="http://www.nunit.org/index.php?p=setupFixture&amp;amp;r=2.5.9"&gt;SetupFixture&lt;/a&gt;, connect with Windows Authentication, and you're all set. MySQL presents a few more challenges, however. First, it needs to be installed. Second, the tests need the correct credentials to connect to the installed MySQL instance.&lt;br /&gt;&lt;br /&gt;One simple way to handle this is to set up a central MySQL instance for testing only. However, this means team members must be on the network to run the tests. There is also the issue of multiple team members running the tests at the same time causing unexpected failures in each other's test runs, or worse, causing unexpected failures in an automated build.&lt;br /&gt;&lt;br /&gt;A better alternative is to keep the MySQL binaries in version control with a known configuration that can be used in test runs. The binary distribution of MySQL is fairly large; however, with the right command line arguments, we only need two files: &lt;i&gt;bin\mysqld-nt.exe&lt;/i&gt; and &lt;i&gt;share\english\errmsg.sys&lt;/i&gt; (or whichever language you want to use). Include both of these as content files in a test project and set the build action to "Copy If Newer". In a SetupFixture, start MySQL with some code like this in the setup method:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;var process = &lt;span class="kwrd"&gt;new&lt;/span&gt; Process();&lt;br /&gt;var arguments = &lt;span class="kwrd"&gt;new&lt;/span&gt;[]&lt;br /&gt;{&lt;br /&gt;    &lt;span class="str"&gt;"--standalone"&lt;/span&gt;,&lt;br /&gt;    &lt;span class="str"&gt;"--console"&lt;/span&gt;,&lt;br /&gt;    &lt;span class="str"&gt;"--basedir=."&lt;/span&gt;,&lt;br /&gt;    &lt;span class="str"&gt;"--language=."&lt;/span&gt;,&lt;br /&gt;    &lt;span class="str"&gt;"--datadir=."&lt;/span&gt;,&lt;br /&gt;    &lt;span class="str"&gt;"--skip-grant-tables"&lt;/span&gt;,&lt;br /&gt;    &lt;span class="str"&gt;"--skip-networking"&lt;/span&gt;,&lt;br /&gt;    &lt;span class="str"&gt;"--enable-named-pipe"&lt;/span&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;process.StartInfo.FileName = &lt;span class="str"&gt;"mysqld-nt.exe"&lt;/span&gt;;&lt;br /&gt;process.StartInfo.Arguments = &lt;span class="kwrd"&gt;string&lt;/span&gt;.Join(&lt;span class="str"&gt;" "&lt;/span&gt;, arguments);&lt;br /&gt;process.StartInfo.UseShellExecute = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;process.StartInfo.CreateNoWindow = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;process.Start();&lt;/pre&gt;&lt;br /&gt;The first two arguments (&lt;i&gt;--standalone&lt;/i&gt; and &lt;i&gt;--console&lt;/i&gt;) tell MySQL to run as a standalone instance and to keep the console window open (i.e. do not run as a service). The next three arguments (&lt;i&gt;--basedir=.&lt;/i&gt;, &lt;i&gt;--language=.&lt;/i&gt; and &lt;i&gt;--datadir=.&lt;/i&gt;) tell MySQL to run from the current directory, load language files (errmsg.sys) from the current directory, and write data files to the current directory. The &lt;i&gt;--skip-grant-tables&lt;/i&gt; argument disables security so that the tests do not need to worry about providing credentials when connecting. The final two arguments (&lt;i&gt;--skip-networking&lt;/i&gt; and &lt;i&gt;--enable-named-pipe&lt;/i&gt;) tell MySQL not to listen for TCP connections and instead allow named pipe connections. This prevents our standalone MySQL instance from interfering with any other MySQL installations on the machine.&lt;br /&gt;&lt;br /&gt;Once the instance has started, we can connect with a connection string like this: &lt;i&gt;Data Source=localhost;Protocol=pipe;&lt;/i&gt;. Finally, kill the MySQL process in the SetupFixture teardown method.&lt;br /&gt;&lt;br /&gt;On my team, we have rolled this functionality (and a few other goodies) into a NUnit addin, but that's a story for another blog post.&lt;br /&gt;&lt;br /&gt;Happy testing!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-8284056490965772311?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/8284056490965772311/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2011/03/testing-mysql-queries-with-nunit.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/8284056490965772311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/8284056490965772311'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2011/03/testing-mysql-queries-with-nunit.html' title='Testing MySQL queries with NUnit'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-3152427946996113415</id><published>2011-02-10T08:56:00.000-05:00</published><updated>2011-02-10T08:56:45.835-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NServiceBus'/><title type='text'>NServiceBus assembly scanning: avoiding unintended consequences</title><content type='html'>The default startup behavior for a NServiceBus endpoint is to scan all assemblies in the deployment directory for any types it might be interested in, for example, message modules and message handlers. This is really handy, but occasionally it can lead to unintended consequences. Fortunately, the With method has a few overloads and one of them takes a list of assemblies to scan. If you want to prevent loading types from any stray assembly that might make it into your deployment directory, change your initialization code to look like this:&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;var assemblies = GetType().Assembly&lt;br /&gt;   .GetReferencedAssemblies()&lt;br /&gt;   .Select(n =&amp;gt; Assembly.Load(n))&lt;br /&gt;   .ToList();&lt;br /&gt;assemblies.Add(GetType().Assembly);&lt;br /&gt;NServiceBus.Configure.With(assemblies);&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This restricts the assembly scanning process to only the assemblies that your endpoint explicitly references. We can extract this code to an extension method so we can use it in other endpoints:&lt;/div&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IEnumerable&amp;lt;Assembly&amp;gt; ReferencedAssemblies(&lt;span class="kwrd"&gt;this&lt;/span&gt; Type type)&lt;br /&gt;{&lt;br /&gt;   var assemblies = type.Assembly&lt;br /&gt;      .GetReferencedAssemblies()&lt;br /&gt;      .Select(n =&amp;gt; Assembly.Load(n))&lt;br /&gt;      .ToList();&lt;br /&gt;   assemblies.Add(GetType().Assembly);&lt;br /&gt;   &lt;span class="kwrd"&gt;return&lt;/span&gt; assemblies;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Now our endpoint initialization looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;NServiceBus.Configure.With(GetType()&lt;br /&gt;   .ReferencedAssemblies());&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-3152427946996113415?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/3152427946996113415/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2011/02/nservicebus-assembly-scanning-avoiding.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/3152427946996113415'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/3152427946996113415'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2011/02/nservicebus-assembly-scanning-avoiding.html' title='NServiceBus assembly scanning: avoiding unintended consequences'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-8361119240742748987</id><published>2010-12-21T06:54:00.001-05:00</published><updated>2010-12-21T06:55:51.144-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Unit Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='NUnit'/><title type='text'>Assert.DoesNotThrow... why does it exist?</title><content type='html'>Take a look at this test:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;[Test]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TestSomething()&lt;br /&gt;{&lt;br /&gt;   Assert.DoesNotThrow(MethodUnderTest);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;It seems to me that it is functionally equivalent to this test:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;[Test]&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TestSomething()&lt;br /&gt;{&lt;br /&gt;    MethodUnderTest();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;In other words, Assert.DoesNotThrow is the same as writing a test with no assertion. Is it really enough that the code runs without throwing an exception? Presumably the method under test is doing &lt;i&gt;something&lt;/i&gt;, so shouldn't you verify those results with a stronger assertion?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-8361119240742748987?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/8361119240742748987/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2010/12/assertdoesnotthrow-why-does-it-exist.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/8361119240742748987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/8361119240742748987'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2010/12/assertdoesnotthrow-why-does-it-exist.html' title='Assert.DoesNotThrow... why does it exist?'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-2793052161917950625</id><published>2010-12-07T07:00:00.000-05:00</published><updated>2011-12-15T10:35:43.363-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='AsyncController'/><title type='text'>AsyncController and custom action invokers</title><content type='html'>If you are trying to get &lt;a href="http://msdn.microsoft.com/en-us/library/ee728598.aspx"&gt;AsyncControllers&lt;/a&gt; to work, you might run into this gem when you try to test your controller:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_HJ5hdQwQyKY/TP4bT2O1mDI/AAAAAAAAAA8/MLOaaiCJMQk/s1600/the_resource_cannot_be_found.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img alt="The resource cannot be found" border="0" height="108" src="http://2.bp.blogspot.com/_HJ5hdQwQyKY/TP4bT2O1mDI/AAAAAAAAAA8/MLOaaiCJMQk/s320/the_resource_cannot_be_found.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;If this happens to you, a &lt;a href="http://stackoverflow.com/questions/3286340/resource-not-found-in-asp-net-mvc-asynccontroller"&gt;custom action invoker&lt;/a&gt;&amp;nbsp;is likely to be the culprit. In my case, I was using &lt;a href="http://www.castleproject.org/container/"&gt;Castle Windsor&lt;/a&gt;, and I had extended &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.controlleractioninvoker(v=VS.90).aspx"&gt;ControllerActionInvoker&lt;/a&gt; to provide dependency injection to my &lt;a href="http://www.asp.net/mvc/tutorials/understanding-action-filters-cs"&gt;action filters&lt;/a&gt;. My action invoker looked something like this:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1481509.js?file=CastleActionInvoker.cs"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;And this is how I had registered the action invoker with Windsor (this assumes you are using a controller factory that is aware of Windsor):&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1481509.js?file=Global.asax.cs"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;All I had to change to fix the problem was to make my custom action invoker inherit &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.async.asynccontrolleractioninvoker(VS.98).aspx"&gt;AsyncControllerActionInvoker&lt;/a&gt; instead:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1481509.js?file=AsyncCastleActionInvoker.cs"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;AsyncControllerActionInvoker implements &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.async.iasyncactioninvoker(VS.98).aspx"&gt;IAsyncActionInvoker&lt;/a&gt; and adds a few new methods. Depending on what you are trying to accomplish with your custom invoker, you may need to override a few of these new methods as well.&lt;br /&gt;&lt;br /&gt;Interestingly enough, I did not have to change how the invoker was registered with Windsor.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-2793052161917950625?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/2793052161917950625/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2010/12/asynccontroller-and-custom-action.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/2793052161917950625'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/2793052161917950625'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2010/12/asynccontroller-and-custom-action.html' title='AsyncController and custom action invokers'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_HJ5hdQwQyKY/TP4bT2O1mDI/AAAAAAAAAA8/MLOaaiCJMQk/s72-c/the_resource_cannot_be_found.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-416038626780649596</id><published>2010-12-06T07:18:00.000-05:00</published><updated>2010-12-06T07:18:18.913-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NServiceBus'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET MVC'/><category scheme='http://www.blogger.com/atom/ns#' term='AsyncController'/><title type='text'>Using AsyncController with NServiceBus</title><content type='html'>With &lt;a href="http://www.nservicebus.com/"&gt;NServiceBus&lt;/a&gt; sometimes you do not want to allow a web request to complete until you have received some response from your message handler. For example, suppose you have defined the following message handler that returns a response code on success:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; TestMessageHandler :&lt;br /&gt;    IHandleMessages&amp;lt;TestMessage&amp;gt;&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; IBus Bus { get; set; }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Handle(TestMessage message)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="rem"&gt;//Do something interesting...&lt;/span&gt;&lt;br /&gt;        Bus.Return(0);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;This is a perfect scenario for using the asynchronous page API. It allows you to execute a potentially long-running operation on a separate thread outside of the IIS thread pool. While this thread is executing, the original request thread is returned to the thread pool. As a result, the asynchronous page API is great for I/O bound operations, since you keep threads in the thread pool ready to service requests and the new thread spends most of its time blocked on I/O. NServiceBus supports the asynchronous page API out of the box:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;Bus.Send(&lt;span class="kwrd"&gt;new&lt;/span&gt; TestMessage()).RegisterWebCallback(callback, state);&lt;/pre&gt;&lt;br /&gt;Unfortunately, RegisterWebCallback does not work with ASP.NET MVC. If you are using ASP.NET MVC, you can use &lt;a href="http://msdn.microsoft.com/en-us/library/ee728598.aspx"&gt;AsyncController&lt;/a&gt;, which was introduced in ASP.NET MVC 2. The following code illustrates how you might use AsyncController to wait for a response the message handler:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; TestController : AsyncController&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; IBus bus;&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; TestController(IBus bus)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;this&lt;/span&gt;.bus = bus;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; IndexAsync()&lt;br /&gt;    {&lt;br /&gt;        AsyncManager.OutstandingOperations.Increment();&lt;br /&gt;&lt;br /&gt;        bus.Send(&lt;span class="kwrd"&gt;new&lt;/span&gt; TestMessage()).Register(Callback);&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; ActionResult IndexCompleted()&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; View();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Callback(&lt;span class="kwrd"&gt;int&lt;/span&gt; responseCode)&lt;br /&gt;    {&lt;br /&gt;        AsyncManager.OutstandingOperations.Decrement();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;As you can see, the AsyncController API is a little awkward (though it is an improvement over the asynchronous page API, in my opinion), but it is a small price to pay for scalability.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-416038626780649596?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/416038626780649596/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2010/12/using-asynccontroller-with-nservicebus.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/416038626780649596'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/416038626780649596'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2010/12/using-asynccontroller-with-nservicebus.html' title='Using AsyncController with NServiceBus'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-7174744657091780620</id><published>2010-08-14T15:07:00.002-04:00</published><updated>2010-08-14T21:11:25.451-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TopShelf'/><category scheme='http://www.blogger.com/atom/ns#' term='NServiceBus'/><category scheme='http://www.blogger.com/atom/ns#' term='CancelKeyPress'/><title type='text'>Ctrl-C and the NServiceBus generic host</title><content type='html'>Ten posts and almost a whole year later, my &lt;a href="http://mikedellanoce.blogspot.com/2009/11/configuring-nservicebus-in-web.html"&gt;very first post about NServiceBus&lt;/a&gt; is still by far my most popular. So here is some more &lt;a href="http://www.nservicebus.com/"&gt;NServiceBus&lt;/a&gt;-y goodness.&lt;br /&gt;&lt;br /&gt;Last week a coworker came to me asking for help with a &lt;a href="http://www.nservicebus.com/SelfHosting.aspx"&gt;self-hosted NServiceBus&lt;/a&gt; application. He had a small console application set up to test NServiceBus and it worked beautifully in all but one case. When he killed the application with Ctrl-C, the message being processed was always lost. At first I thought maybe the application was not using a &lt;a href="http://www.nservicebus.com/Transactions.aspx"&gt;transactional endpoint&lt;/a&gt;, but it was configured to do so. I did not see the same behavior with the &lt;a href="http://www.nservicebus.com/GenericHost.aspx"&gt;generic host&lt;/a&gt; running in console mode, so I figured the generic host was handling Ctrl-C somehow. A quick search turned up the &lt;a href="http://stackoverflow.com/questions/177856/how-do-i-trap-ctrl-c-in-a-c-console-app"&gt;CancelKeyPress event&lt;/a&gt;. I opened up the generic host in &lt;a href="http://www.red-gate.com/products/reflector/"&gt;reflector&lt;/a&gt;, and, on a hunch, navigated to the TopShelf.Internal.Hosts namespace (the generic host &lt;a href="http://www.udidahan.com/2010/08/01/cautiously-merging-il/"&gt;internalizes&lt;/a&gt; another excellent open source project called &lt;a href="http://code.google.com/p/topshelf/"&gt;TopShelf&lt;/a&gt;). Sure enough, the TopShelf console host handles the CancelKeyPress event, and ultimately allows all of the worker threads in NServiceBus to finish handling messages before shutting down.&lt;br /&gt;&lt;br /&gt;One question this brought up is what happens if someone pulls the plug on my machine after a message has been received, but before it has been processed? My impression was that a transactional endpoint would take care of this, but now I'm not so sure.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-7174744657091780620?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/7174744657091780620/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2010/08/ctrl-c-and-nservicebus-generic-host.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/7174744657091780620'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/7174744657091780620'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2010/08/ctrl-c-and-nservicebus-generic-host.html' title='Ctrl-C and the NServiceBus generic host'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-2339728428573909886</id><published>2010-07-27T20:32:00.001-04:00</published><updated>2010-07-27T20:32:41.373-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><title type='text'>Over-testing: the data-driven edition</title><content type='html'>Learning to test at the right level of abstraction is tough. A common mistake involves the abuse of data-driven testing tools. Data-driven testing tools, like &lt;a href="http://www.nunit.org/index.php?p=testCase&amp;amp;r=2.5.6"&gt;TestCase&lt;/a&gt; in NUnit, are convenient and powerful. You can write a lot of tests really fast, but if you're not careful, you can end up repeating yourself.&lt;br /&gt;&lt;br /&gt;For example, suppose we define the following (woefully oversimplified) utility function to test if a string is a valid email address:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsValidEmail(&lt;span class="kwrd"&gt;string&lt;/span&gt; email)&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; Regex.IsMatch(email, &lt;span class="str"&gt;@"\w+@\w+\.com"&lt;/span&gt;);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;The test suite for this function should be complete. A data-driven approach works really well here:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;[TestCase(&lt;span class="str"&gt;"a@test.com"&lt;/span&gt;)]&lt;br /&gt;[TestCase(&lt;span class="str"&gt;"1@test.com"&lt;/span&gt;)]&lt;br /&gt;&lt;span class="rem"&gt;//... lots more&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TestValidEmail(&lt;span class="kwrd"&gt;string&lt;/span&gt; email)&lt;br /&gt;{&lt;br /&gt;    Assert.That(IsValidEmail(email));&lt;br /&gt;}&lt;br /&gt;[TestCase(&lt;span class="kwrd"&gt;null&lt;/span&gt;)]&lt;br /&gt;[TestCase(&lt;span class="str"&gt;"not an email address"&lt;/span&gt;)]&lt;br /&gt;&lt;span class="rem"&gt;//... and so on&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TestInvalidEmail(&lt;span class="kwrd"&gt;string&lt;/span&gt; email)&lt;br /&gt;{&lt;br /&gt;    Assert.That(IsValidEmail(email), Is.False);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Now, suppose we use this method in some application logic:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SendConfirmation(&lt;span class="kwrd"&gt;string&lt;/span&gt; message, &lt;span class="kwrd"&gt;string&lt;/span&gt; email)&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!IsValidEmail(email))&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; ArgumentException(&lt;span class="str"&gt;"email"&lt;/span&gt;);&lt;br /&gt;    }&lt;br /&gt;    SendEmail(message, email);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Awesome, let's test this bad boy... er, I mean here's the test we wrote before writing the method:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;[TestCase(&lt;span class="str"&gt;"a@test.com"&lt;/span&gt;)]&lt;br /&gt;[TestCase(&lt;span class="str"&gt;"1@test.com"&lt;/span&gt;)]&lt;br /&gt;&lt;span class="rem"&gt;//... lots more&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TestSendEmailIfValid(&lt;span class="kwrd"&gt;string&lt;/span&gt; email)&lt;br /&gt;{&lt;br /&gt;    SendConfirmation(&lt;span class="str"&gt;"test"&lt;/span&gt;, email);&lt;br /&gt;    &lt;span class="rem"&gt;//Assert sends email...&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;[TestCase(&lt;span class="kwrd"&gt;null&lt;/span&gt;)]&lt;br /&gt;[TestCase(&lt;span class="str"&gt;"not an email address"&lt;/span&gt;)]&lt;br /&gt;&lt;span class="rem"&gt;//... and so on&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TestSendEmailThrowsIfInvalid(&lt;span class="kwrd"&gt;string&lt;/span&gt; email)&lt;br /&gt;{&lt;br /&gt;    SendConfirmation(&lt;span class="str"&gt;"test"&lt;/span&gt;, email);&lt;br /&gt;    &lt;span class="rem"&gt;//Assert throws exception...&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Okay, stop... do we really need to re-test every single valid and invalid email address? Data-driven tests make this easy, but that doesn't make it right. In this function, there are really only two paths that matter: an invalid email address throws an exception, and sending an email successfully. Let's try again:&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TestSendEmailIfValid(&lt;span class="kwrd"&gt;string&lt;/span&gt; email)&lt;br /&gt;{&lt;br /&gt;    SendConfirmation(&lt;span class="str"&gt;"test"&lt;/span&gt;, &lt;span class="str"&gt;"validemail@test.com"&lt;/span&gt;);&lt;br /&gt;    &lt;span class="rem"&gt;//Assert sends email...&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; TestSendEmailThrowsIfInvalid()&lt;br /&gt;{&lt;br /&gt;    SendConfirmation(&lt;span class="str"&gt;"test"&lt;/span&gt;, &lt;span class="str"&gt;"not an email address"&lt;/span&gt;);&lt;br /&gt;    &lt;span class="rem"&gt;//Assert throws exception...&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Mockists might even take this so far as to stub out the IsValidEmail function for the purposes of testing this function, but for this simple case, it might be overkill since IsValidEmail has no external dependencies to begin with.&lt;br /&gt;&lt;br /&gt;In the real world, this kind of mistake is harder to spot. Generally, if you have an explosion of TestCase attributes covering all kinds of permutations, consider revisiting the code under test. There may be some opportunities to simplify both your code and your test suite.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-2339728428573909886?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/2339728428573909886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2010/07/over-testing-data-driven-edition.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/2339728428573909886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/2339728428573909886'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2010/07/over-testing-data-driven-edition.html' title='Over-testing: the data-driven edition'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-8419651317771480240</id><published>2010-07-17T11:33:00.001-04:00</published><updated>2010-07-17T11:35:44.523-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Patterns'/><title type='text'>JavaScript - apply invocation pattern part 2</title><content type='html'>In my &lt;a href="http://mikedellanoce.blogspot.com/2010/07/things-your-parents-never-told-you.html"&gt;last post&lt;/a&gt; I promised a real-world example of the apply invocation pattern. The truth is it was getting late, and I didn't feel like writing anymore. However, one of my coworkers called me out, most likely because he's a JavaScript ninja and wants to put me in my place. In an effort to deny him the satisfaction, I'll steal an example from people who are smarter than I.&lt;br /&gt;&lt;br /&gt;If you use &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt;, you've probably used the &lt;a href="http://api.jquery.com/jQuery.each/"&gt;each function&lt;/a&gt; at some point. The each function works something like this (what follows is a &lt;b&gt;vast &lt;/b&gt;oversimplification, see &lt;a href="http://github.com/jquery/jquery/blob/master/src/core.js"&gt;here&lt;/a&gt; for the actual implementation):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;jQuery.extend({&lt;br /&gt;  each: function(array, callback) {&lt;br /&gt;    for (var i = 0; i &amp;lt; array.length; i++) {&lt;br /&gt;      var value = array[i];&lt;br /&gt;&lt;br /&gt;      //Apply callback with "this" as the current value&lt;br /&gt;      callback.apply(value, [i, value]);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;});&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now we can use the each function like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;var sentence = '';&lt;br /&gt;var words = ['hello', ' ', 'world', '!'];&lt;br /&gt;jQuery.each(words, function() {&lt;br /&gt;  sentence += this;&lt;br /&gt;});&lt;br /&gt;//sentence == 'hello world!'&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-8419651317771480240?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/8419651317771480240/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2010/07/javascript-apply-invocation-pattern.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/8419651317771480240'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/8419651317771480240'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2010/07/javascript-apply-invocation-pattern.html' title='JavaScript - apply invocation pattern part 2'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-4090899042505974808</id><published>2010-07-13T22:10:00.002-04:00</published><updated>2010-07-17T11:34:01.192-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Patterns'/><title type='text'>Things your parents never told you about JavaScript - Apply invocation pattern</title><content type='html'>So, yeah, it's been a while... okay, it's been more than a while. I'm sure my 8 followers missed me. Anyway, I recently had the opportunity to learn a whole mess of new stuff, and I wanted to start writing some of it down. I had a 3 week fling with Ruby, followed by a longer affair with JavaScript. I was a static language guy for the last 3 years, so all this dynamic nonsense had my head spinning... and you know what?&lt;br /&gt;&lt;br /&gt;I &lt;i&gt;liked&lt;/i&gt; it.&lt;br /&gt;&lt;br /&gt;I always thought of JavaScript development as painful; a sort of necessary evil. Turns out there's an &lt;i&gt;obscenely&lt;/i&gt;&amp;nbsp;powerful language there, if you go looking for it (incidentally, start by looking &lt;a href="http://www.amazon.com/gp/product/B0026OR2ZY"&gt;here&lt;/a&gt;). Among those powerful features are&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/First-class_function"&gt;first-class functions&lt;/a&gt;. For example, suppose I run the following code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;var greeter = {&lt;br /&gt;  name: 'Mike',&lt;br /&gt;  greet: function() {&lt;br /&gt;    return 'hello ' + this.name;&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;greeter.greet(); // -&amp;gt; 'hello Mike'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Nothing shocking there, right? Well, I can actually reach into the greeter object and &lt;i&gt;steal&lt;/i&gt;&amp;nbsp;the greet function:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;var greet = greeter.greet;&lt;br /&gt;greet(); // -&amp;gt; 'hello '&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Okay, kind of cool, but not quite the expected result. Where did my name go? When you grab a function that references &lt;i&gt;this&lt;/i&gt; and invoke it, you need to tell JavaScript what context you want to execute it in. The built-in JavaScript Function object has a method called apply which lets you set the value of &lt;i&gt;this&lt;/i&gt;&amp;nbsp;(it also lets you pass an argument array if you want to):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;var bob = {&lt;br /&gt;  name: 'Bob'&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;greet.apply(bob); // -&amp;gt; 'hello Bob'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This is called the &lt;i&gt;apply invocation pattern&lt;/i&gt;. What can you do with it? That'll have to wait for &lt;a href="http://mikedellanoce.blogspot.com/2010/07/javascript-apply-invocation-pattern.html"&gt;another post&lt;/a&gt;...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-4090899042505974808?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/4090899042505974808/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2010/07/things-your-parents-never-told-you.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/4090899042505974808'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/4090899042505974808'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2010/07/things-your-parents-never-told-you.html' title='Things your parents never told you about JavaScript - Apply invocation pattern'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-4996072000474242025</id><published>2010-03-11T06:58:00.000-05:00</published><updated>2010-03-11T06:58:34.413-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Exception handling'/><title type='text'>Re-throwing exceptions in C#</title><content type='html'>&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What is the difference between the following two blocks of code?&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;// #1&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; HandleException()&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="rem"&gt;//Do something...&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception e)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;throw&lt;/span&gt; e;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="rem"&gt;// #2&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;void&lt;/span&gt; HandleException()&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="rem"&gt;//Do something...&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception e)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;throw&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Both blocks catch and re-throw an exception. The first block re-throws the caught exception, the second block does not specify anything to throw. The main difference between these blocks becomes apparent when the exception is logged higher up in the call stack. The stack trace for the first code block will be missing anything that came before the throw. The second code block will contain the full stack trace. This can be the difference between life and death when trying to diagnose an issue in production.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-4996072000474242025?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/4996072000474242025/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2010/03/re-throwing-exceptions-in-c.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/4996072000474242025'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/4996072000474242025'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2010/03/re-throwing-exceptions-in-c.html' title='Re-throwing exceptions in C#'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-7676708681574335971</id><published>2010-01-06T06:50:00.001-05:00</published><updated>2010-01-06T06:52:04.686-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Castle'/><category scheme='http://www.blogger.com/atom/ns#' term='Inversion of Control'/><title type='text'>Castle Windsor: Order Matters</title><content type='html'>I've been learning a lot about&amp;nbsp;&lt;a href="http://www.castleproject.org/container/index.html"&gt;Castle Windsor&lt;/a&gt;&amp;nbsp;lately. I ran into something that surprised me yesterday. Suppose you have the following class hierarchy:&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;interface&lt;/span&gt; Service&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; ServiceA : Service&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; ServiceB : Service&lt;br /&gt;{&lt;br /&gt;}&lt;/pre&gt;What do you think the output from this code will be?&lt;br /&gt;&lt;pre class="csharpcode"&gt;var container = &lt;span class="kwrd"&gt;new&lt;/span&gt; WindsorContainer();&lt;br /&gt;&lt;br /&gt;container.Register(Component&lt;br /&gt;    .For&amp;lt;Service&amp;gt;()&lt;br /&gt;    .ImplementedBy&amp;lt;ServiceA&amp;gt;());&lt;br /&gt;container.Register(Component&lt;br /&gt;    .For&amp;lt;Service&amp;gt;()&lt;br /&gt;    .ImplementedBy&amp;lt;ServiceB&amp;gt;()&lt;br /&gt;    .Named(&lt;span class="str"&gt;"serviceb"&lt;/span&gt;));&lt;br /&gt;&lt;br /&gt;var service = container.Resolve&amp;lt;Service&amp;gt;();&lt;br /&gt;&lt;br /&gt;Console.WriteLine(service.GetType().Name);&lt;/pre&gt;If you said &lt;i&gt;ServiceA&lt;/i&gt;, then you were right! Now, what about the output from this code?&lt;br /&gt;&lt;pre class="csharpcode"&gt;var container = &lt;span class="kwrd"&gt;new&lt;/span&gt; WindsorContainer();&lt;br /&gt;&lt;br /&gt;container.Register(Component&lt;br /&gt;    .For&amp;lt;Service&amp;gt;()&lt;br /&gt;    .ImplementedBy&amp;lt;ServiceB&amp;gt;()&lt;br /&gt;    .Named(&lt;span class="str"&gt;"serviceb"&lt;/span&gt;));&lt;br /&gt;container.Register(Component&lt;br /&gt;    .For&amp;lt;Service&amp;gt;()&lt;br /&gt;    .ImplementedBy&amp;lt;ServiceA&amp;gt;());&lt;br /&gt;&lt;br /&gt;var service = container.Resolve&amp;lt;Service&amp;gt;();&lt;br /&gt;&lt;br /&gt;Console.WriteLine(service.GetType().Name);&lt;/pre&gt;If you said &lt;i&gt;ServiceB&lt;/i&gt;, then maybe the title of this post gave the answer away. I expected the named service to be a special case. In other words, I thought asking for a &lt;i&gt;Service&lt;/i&gt;&amp;nbsp;implementation would always give me &lt;i&gt;ServiceA&lt;/i&gt;, unless I specifically asked for &lt;i&gt;ServiceB&lt;/i&gt;&amp;nbsp;by name.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-7676708681574335971?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/7676708681574335971/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2010/01/castle-windsor-order-matters.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/7676708681574335971'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/7676708681574335971'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2010/01/castle-windsor-order-matters.html' title='Castle Windsor: Order Matters'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-2978374209619804566</id><published>2009-12-14T06:59:00.006-05:00</published><updated>2011-12-14T20:10:41.528-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Model Binding'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET MVC'/><title type='text'>ASP.NET MVC XML Model Binder</title><content type='html'>&lt;b&gt;Update 12/14/2011&lt;/b&gt;&lt;br /&gt;This is one of my most highly viewed posts. Unfortunately, this post applies to version 1 of ASP.NET MVC (it might also work with version 2 with some small modifications). If that is what you are looking for, then please read on! Otherwise, for more relevant coverage of this topic I recommend &lt;a href="http://lostechies.com/jimmybogard/2011/06/24/model-binding-xml-in-asp-net-mvc-3/"&gt;Jimmy Bogard's post&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I needed a way to receive raw XML in my action methods, rather than form-encoded values. Model binding makes it a piece of cake:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1479347.js?file=XmlModelBinder1.cs"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;In my action method all I have to do is apply the model binder attribute:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1479347.js?file=Controller1.cs"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Now the edit action receives an XML string. Even better, I can get a strongly typed object if it is serializable:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1479347.js?file=XmlModelBinder2.cs"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Now my action method looks like this:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1479347.js?file=Controller2.cs"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;The model binder attribute is a little too verbose for my taste, so I wrote a custom model binder attribute:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1479347.js?file=BindXmlAttribute.cs"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Finally my action method is nice and readable:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1479347.js?file=Controller3.cs"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-2978374209619804566?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/2978374209619804566/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2009/12/aspnet-mvc-xml-model-binder.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/2978374209619804566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/2978374209619804566'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2009/12/aspnet-mvc-xml-model-binder.html' title='ASP.NET MVC XML Model Binder'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-3846783327404367645</id><published>2009-12-08T07:00:00.000-05:00</published><updated>2009-12-08T07:00:20.585-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Automation'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>"Good Enough" Test Automation</title><content type='html'>If you are practicing Agile and you want to stay releasable at the end of every iteration, &lt;a href="http://every2weeks.wordpress.com/2008/03/22/agile-axiom-2-without-automation-it-is-mathematically-impossible-to-stay-releasable-at-the-end-of-every-iteration/"&gt;you must automate your tests&lt;/a&gt;. If you do not automate, one of two things will happen:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Your velocity will decrease each sprint as you need to reserve more and more time for regression testing.&lt;/li&gt;&lt;li&gt;You will not run (or will forget to run) regression tests, and you run the risk of breaking something unintentionally. Best-case, your testers will catch any problems before release. Worst-case, your customers will find problems after release.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Now, here's the fun part: you have 2-3 weeks to build and test something potentially releasable. How can you possibly squeeze test automation into that time frame? The same way you attack that next killer feature: start small and iterate.&lt;br /&gt;&lt;br /&gt;A few days ago I was testing some changes to a multi-step online signup process. The current code base is, shall we say, less than testable at the unit level. As a result, all testing for this feature has been manual in the past. After a few manual test runs, introducing some automated tests at the browser level seemed like a good idea. I immediately thought about continuous integration, but quickly realized dealing with all the necessary data setup and tear-down was going to take several days to get right. All I needed at that moment was a script to fill out the forms and click through the whole process. I coded a short &lt;a href="http://watir.com/"&gt;Watir&lt;/a&gt; script, ran it a few times, and visually verified the process still worked end-to-end.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If all you need is a script to do the boring, repetitive parts of testing for you, write the script. If the script is useful, you'll keep coming back to it, and eventually get it running under continuous integration. Just take the first step, choose a tool, and start automating.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-3846783327404367645?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/3846783327404367645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2009/12/good-enough-test-automation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/3846783327404367645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/3846783327404367645'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2009/12/good-enough-test-automation.html' title='&quot;Good Enough&quot; Test Automation'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-7303583146006023037</id><published>2009-12-02T08:23:00.000-05:00</published><updated>2009-12-02T08:25:51.985-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.NET'/><title type='text'>Missing reports in CruiseControl.NET</title><content type='html'>My team experienced a spell of build failures last week due to broken unit tests. It wasn't a big deal, broken tests happen from time to time, the breaker simply fixes them and life goes on. However, something strange happened when we looked at the build report to see what failed.&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;a href="http://1.bp.blogspot.com/_HJ5hdQwQyKY/SxZpAJGskWI/AAAAAAAAAAM/BGWtZCeTsoU/s1600-h/invisible_tests.png" imageanchor="1"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_HJ5hdQwQyKY/SxZpAJGskWI/AAAAAAAAAAM/BGWtZCeTsoU/s320/invisible_tests.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The report showed that the &lt;a href="http://www.nunit.org/"&gt;NUnit&lt;/a&gt; process had exited with an error code, but the unit test summary claimed that no tests had been run.&lt;br /&gt;&lt;br /&gt;I logged in to the build server and checked out the build log. The unit test results were there, and I was able to search the log to find which ones failed, but obviously nobody wants to log in to the build server and search through a text file whenever a unit test breaks. On closer inspection, I realized that &lt;i&gt;all&lt;/i&gt;&amp;nbsp;of&amp;nbsp;the XML data for the test results were wrapped in a CDATA section. One developer pointed out that this was likely caused by strange characters in the test results, and the documentation for the&amp;nbsp;&lt;a href="http://confluence.public.thoughtworks.org/display/CCNET/File+Merge+Task"&gt;file merge task&lt;/a&gt;&amp;nbsp;confirmed the possibility. However, my team has amassed about 2,500 unit tests, so finding the offending character in approximately 10,000 lines of test results would have been difficult to say the least.&lt;br /&gt;&lt;br /&gt;After some digging, I found out that &lt;a href="http://ccnet.thoughtworks.com/"&gt;CruiseControl.NET&lt;/a&gt; logs a debug message when a file cannot be merged because it contains invalid XML. I opened up the log (ccnet.log by default) and a quick search for &lt;i&gt;output is not valid XML&lt;/i&gt;&amp;nbsp;revealed the exact line number in the test results that caused the file merge task to fail. Now we are happily integrating continuously once again.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-7303583146006023037?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/7303583146006023037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2009/12/missing-reports-in-cruisecontrolnet.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/7303583146006023037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/7303583146006023037'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2009/12/missing-reports-in-cruisecontrolnet.html' title='Missing reports in CruiseControl.NET'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_HJ5hdQwQyKY/SxZpAJGskWI/AAAAAAAAAAM/BGWtZCeTsoU/s72-c/invisible_tests.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9194677942308742051.post-2193766296316130390</id><published>2009-11-25T08:22:00.000-05:00</published><updated>2009-11-25T08:22:14.659-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='NServiceBus'/><title type='text'>Configuring NServiceBus In Web Applications</title><content type='html'>My team recently started using&amp;nbsp;&lt;a href="http://www.nservicebus.com/"&gt;NServiceBus&lt;/a&gt;&amp;nbsp;for a new project. It has gone extremely well for the most part. Messaging can be tricky, and a tool like NServiceBus can lower the barrier to entry and gently guides developers towards messaging best practices.&lt;br /&gt;&lt;br /&gt;Like any tool, NServiceBus has a learning curve, and there were a few problems along the way. The biggest was an issue with configuring web applications as endpoints. Each web application used the fluent configuration API in the Application_Start event handler like so:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;NServiceBus.Configure.With()...&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It worked fine in almost all cases. However, when one application was deployed to IIS, the configuration code was throwing&amp;nbsp;&lt;a href="http://msdn.microsoft.com/en-us/library/system.typeloadexception.aspx"&gt;inexplicable errors&lt;/a&gt;. My team lost about a week trying to figure out what was going on, and eventually started investigating workarounds in order to meet the deadline. Workarounds usually result in their own&amp;nbsp;&lt;a href="http://programmer.97things.oreilly.com/wiki/index.php/The_Longevity_of_Interim_Solutions"&gt;unique set of problems&lt;/a&gt;, which I desperately wanted to avoid. Finally, a long session with&amp;nbsp;&lt;a href="http://www.red-gate.com/products/reflector/"&gt;reflector&lt;/a&gt;&amp;nbsp;revealed the problem:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;NServiceBus.Configure.WithWeb()...&lt;/pre&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;The difference between the two methods is subtle. The former tells NServiceBus to scan&amp;nbsp;&lt;a href="http://msdn.microsoft.com/en-us/library/system.appdomain.basedirectory.aspx"&gt;AppDomain.BaseDirectory&lt;/a&gt;&amp;nbsp;for assemblies, while the latter tells NServiceBus to scan&amp;nbsp;&lt;a href="http://msdn.microsoft.com/en-us/library/system.appdomain.dynamicdirectory.aspx"&gt;AppDomain.DynamicDirectory&lt;/a&gt;. The reason this affected one application in particular was because of how that application is deployed. Different versions of the application are deployed in virtual directories under the same web application in IIS, so there was a mismatch between some assembly versions.&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;The NServiceBus samples demonstrate the use of the WithWeb method. Had we paid more attention to the samples, we might have completely avoided this headache.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9194677942308742051-2193766296316130390?l=www.mikedellanoce.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.mikedellanoce.com/feeds/2193766296316130390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.mikedellanoce.com/2009/11/configuring-nservicebus-in-web.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/2193766296316130390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9194677942308742051/posts/default/2193766296316130390'/><link rel='alternate' type='text/html' href='http://www.mikedellanoce.com/2009/11/configuring-nservicebus-in-web.html' title='Configuring NServiceBus In Web Applications'/><author><name>Michael Dellanoce</name><uri>https://profiles.google.com/102857576036625579093</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh6.googleusercontent.com/-MFkWo_04QKs/AAAAAAAAAAI/AAAAAAAAAFM/kr05Qi_bM_Y/s512-c/photo.jpg'/></author><thr:total>2</thr:total></entry></feed>
