<?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-6566548306419873706</id><updated>2012-02-16T22:41:30.038-06:00</updated><category term='C#'/><category term='NUnit'/><category term='MSAccess'/><category term='continuous integration'/><category term='tools'/><category term='debugging'/><category term='refactoring'/><category term='Subversion'/><category term='SourceSafe'/><category term='FxCop'/><category term='coding'/><category term='CruiseControl.Net'/><category term='VS2005'/><category term='database'/><category term='misc'/><title type='text'>AutomaticChainsaw</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>74</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-4472866656924484367</id><published>2010-08-31T16:53:00.001-05:00</published><updated>2010-08-31T16:57:24.103-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FxCop'/><title type='text'>Correctly disposing of objects - implement IDisposable</title><content type='html'>To continue with our &lt;a href="http://automaticchainsaw.blogspot.com/2010/02/fxcop-starting-point.html" title="FxCop: A starting point"&gt;FxCop backlog&lt;/a&gt;, we are going to look at a couple rules dealing with IDisposable. Consider the following class:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;}??\fs20   \cf3 public\cf0  \cf3 class\cf0  \cf4 TimedProcessor\par ??\cf0   \{\par ??      \cf4 Timer\cf0  startTimer = \cf3 new\cf0  \cf4 Timer\cf0 ();\par ??\par ??      \cf3 public\cf0  TimedProcessor(\cf3 double\cf0  interval)\par ??      \{\par ??          startTimer = \cf3 new\cf0  \cf4 Timer\cf0 (interval);\par ??          startTimer.Elapsed += timer_Elapsed;\par ??      \}\par ??\par ??      \cf3 void\cf0  timer_Elapsed(\cf3 object\cf0  sender, \cf4 ElapsedEventArgs\cf0  e)\par ??      \{\par ??          \cf4 Console\cf0 .WriteLine(\cf5 "Do work here"\cf0 );\par ??      \}\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;TimedProcessor&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: #2b91af;"&gt;Timer&lt;/span&gt; startTimer = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Timer&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; TimedProcessor(&lt;span style="color: blue;"&gt;double&lt;/span&gt; interval)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; startTimer = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Timer&lt;/span&gt;(interval);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; startTimer.Elapsed += timer_Elapsed;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;void&lt;/span&gt; timer_Elapsed(&lt;span style="color: blue;"&gt;object&lt;/span&gt; sender, &lt;span style="color: #2b91af;"&gt;ElapsedEventArgs&lt;/span&gt; e)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515;"&gt;"Do work here"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Running FxCop on this will report a violation of the rule &lt;a href="http://msdn.microsoft.com/en-us/library/ms182172.aspx"&gt;Types that own disposable fields should be disposable&lt;/a&gt;. The problem is that the startTimer field is of type Timer, which implements IDisposable. To properly use the timer, we need to call its Dispose method as soon as we are done with it.  The solution is to implement IDisposable on our class and make sure we call startTimer.Dispose().&lt;br /&gt;&lt;br /&gt;The class after fixing the violation:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;}??\fs20   \cf3 public\cf0  \cf3 class\cf0  \cf4 TimedProcessor\cf0  : \cf4 IDisposable\par ??\cf0   \{\par ??      \cf4 Timer\cf0  startTimer = \cf3 new\cf0  \cf4 Timer\cf0 ();\par ??\par ??      \cf3 public\cf0  TimedProcessor(\cf3 double\cf0  interval)\par ??      \{\par ??          startTimer = \cf3 new\cf0  \cf4 Timer\cf0 (interval);\par ??          startTimer.Elapsed += timer_Elapsed;\par ??      \}\par ??\par ??      \cf3 void\cf0  timer_Elapsed(\cf3 object\cf0  sender, \cf4 ElapsedEventArgs\cf0  e)\par ??      \{\par ??          \cf4 Console\cf0 .WriteLine(\cf5 "Do work here"\cf0 );\par ??      \}\par ??\par ??      \cf3 public\cf0  \cf3 void\cf0  Dispose()\par ??      \{\par ??          \cf3 if\cf0  (startTimer != \cf3 null\cf0 )\par ??              startTimer.Dispose();\par ??      \}\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;TimedProcessor&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;IDisposable&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: #2b91af;"&gt;Timer&lt;/span&gt; startTimer = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Timer&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; TimedProcessor(&lt;span style="color: blue;"&gt;double&lt;/span&gt; interval)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; startTimer = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Timer&lt;/span&gt;(interval);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; startTimer.Elapsed += timer_Elapsed;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;void&lt;/span&gt; timer_Elapsed(&lt;span style="color: blue;"&gt;object&lt;/span&gt; sender, &lt;span style="color: #2b91af;"&gt;ElapsedEventArgs&lt;/span&gt; e)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: #2b91af;"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515;"&gt;"Do work here"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Dispose()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (startTimer != &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; startTimer.Dispose();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Note that I check for null before calling Dispose. If an error elsewhere left the object in an invalid state, we don't want our Dispose method to throw a NullReferenceException. &lt;br /&gt;&lt;br /&gt;Now, say we add a second field called endTimer.  Running FxCop now will report a violation of the rule &lt;a href="http://msdn.microsoft.com/en-us/library/ms182328.aspx"&gt;Disposable fields should be disposed&lt;/a&gt;.  In this case we have already implemented IDisposable, but not all of our disposable fields have been addressed.  To fix this, we need to modify our Dispose method slightly:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;}??\fs20   \cf3 public\cf0  \cf3 void\cf0  Dispose()\par ??  \{\par ??      \cf3 if\cf0  (startTimer != \cf3 null\cf0 )\par ??          startTimer.Dispose();\par ??\par ??      \cf3 if\cf0  (endTimer != \cf3 null\cf0 )\par ??          endTimer.Dispose();\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Dispose()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (startTimer != &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; startTimer.Dispose();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (endTimer != &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; endTimer.Dispose();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-4472866656924484367?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/4472866656924484367/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/08/correctly-disposing-of-objects.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/4472866656924484367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/4472866656924484367'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/08/correctly-disposing-of-objects.html' title='Correctly disposing of objects - implement IDisposable'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-2639062783565853665</id><published>2010-07-14T11:10:00.000-05:00</published><updated>2010-07-14T11:10:27.185-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FxCop'/><title type='text'>A custom FxCop rule - calling Debug methods</title><content type='html'>While working on a recent production issue, we ran into an interesting problem. We suspected an exception was being thrown when calling an external site, but we couldn't prove it.  Our usual method of exception handling is to save the details to a rolling log file.  This particular service, however, was failing without leaving behind any info as to why. Digging through the code revealed a catch block similar to this:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;}??\fs20   \cf3 catch\cf0  (\cf4 Exception\cf0  ex)\par ??  \{\par ??      \cf4 Debug\cf0 .WriteLine(ex.ToString());\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;catch&lt;/span&gt; (&lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt; ex)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: #2b91af;"&gt;Debug&lt;/span&gt;.WriteLine(ex.ToString());&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;For now, ignore the fact that you will only see output using something like &lt;a href="http://automaticchainsaw.blogspot.com/2007/11/quick-and-dirty-debugging-debugview-and.html"&gt;DebugView&lt;/a&gt;. The real problem is that when the code is compiled in Release mode, calls to Debug.WriteLine are removed completely.  So in the example above, the catch block will be empty.&lt;br /&gt;&lt;br /&gt;To reduce the odds of this sort of thing happening in the future, I decided to write a custom FxCop rule to locate any calls to methods that had been tagged with a "Debug" conditional. It wasn't as easy as I had expected, but there is an excellent &lt;a href="http://www.binarycoder.net/fxcop/"&gt;tutorial&lt;/a&gt; on the subject. The only difficulty I had was in locating the ConditionalSymbol property in the class tree.&lt;br /&gt;&lt;br /&gt;For anyone interested, here is the xml rule file:&lt;br /&gt;&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red163\green21\blue21;\red255\green0\blue0;\red0\green0\blue0;}??\fs20 \cf1 \tab &amp;lt;?\cf3 xml\cf1  \cf4 version\cf1 =\cf0 "\cf1 1.0\cf0 "\cf1  \cf4 encoding\cf1 =\cf0 "\cf1 utf-8\cf0 "\cf1  ?&amp;gt;\par ??\tab &amp;lt;\cf3 Rules\cf1  \cf4 FriendlyName\cf1 =\cf0 "\cf1 Custom Rules\cf0 "\cf1 &amp;gt;\par ??\tab \tab &amp;lt;\cf3 Rule\cf1  \cf4 TypeName\cf1 =\cf0 "\cf1 DoNotCallDebugConditionalMethods\cf0 "\cf1  \cf4 Category\cf1 =\cf0 "\cf1 CustomRules\cf0 "\cf1  \cf4 CheckId\cf1 =\cf0 "\cf1 PG1001\cf0 "\cf1 &amp;gt;\par ??\tab \tab \tab &amp;lt;\cf3 Name\cf1 &amp;gt;\cf0 Do not call debug conditional methods\cf1 &amp;lt;/\cf3 Name\cf1 &amp;gt;\par ??\tab \tab \tab &amp;lt;\cf3 Description\cf1 &amp;gt;\cf0 Calls to methods marked with the DEBUG conditional will be removed\par ??\tab \tab \tab from Release builds.\cf1 &amp;lt;/\cf3 Description\cf1 &amp;gt;\par ??\tab \tab \tab &amp;lt;\cf3 Url\cf1 &amp;gt;&amp;lt;/\cf3 Url\cf1 &amp;gt;\par ??\tab \tab \tab &amp;lt;\cf3 Resolution\cf1 &amp;gt;\cf0 Replace the call to '\{0\}' with a more appropriate call\cf1 &amp;lt;/\cf3 Resolution\cf1 &amp;gt;\par ??\tab \tab \tab &amp;lt;\cf3 MessageLevel\cf1  \cf4 Certainty\cf1 =\cf0 "\cf1 100\cf0 "\cf1 &amp;gt;\cf0 Warning\cf1 &amp;lt;/\cf3 MessageLevel\cf1 &amp;gt;\par ??\tab \tab \tab &amp;lt;\cf3 Email\cf1 &amp;gt;&amp;lt;/\cf3 Email\cf1 &amp;gt;\par ??\tab \tab \tab &amp;lt;\cf3 FixCategories\cf1 &amp;gt;\cf0 DependsOnFix\cf1 &amp;lt;/\cf3 FixCategories\cf1 &amp;gt;\par ??\tab \tab \tab &amp;lt;\cf3 Owner\cf1 &amp;gt;&amp;lt;/\cf3 Owner\cf1 &amp;gt;\par ??\tab \tab &amp;lt;/\cf3 Rule\cf1 &amp;gt;\par ??\tab &amp;lt;/\cf3 Rules\cf1 &amp;gt;}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;?&lt;/span&gt;&lt;span style="color: #a31515;"&gt;xml&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;version&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;1.0&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;encoding&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;utf-8&lt;/span&gt;"&lt;span style="color: blue;"&gt; ?&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Rules&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;FriendlyName&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;Custom Rules&lt;/span&gt;"&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Rule&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;TypeName&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;DoNotCallDebugConditionalMethods&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;Category&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;CustomRules&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;CheckId&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;PG1001&lt;/span&gt;"&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Name&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;Do not call debug conditional methods&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Name&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Description&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;Calls to methods marked with the DEBUG conditional will be removed&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; from Release builds.&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Description&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Url&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Url&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Resolution&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;Replace the call to '{0}' with a more appropriate call&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Resolution&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;MessageLevel&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;Certainty&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;100&lt;/span&gt;"&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;Warning&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;MessageLevel&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Email&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Email&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;FixCategories&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;DependsOnFix&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;FixCategories&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Owner&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Owner&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Rule&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;Rules&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;And the code:&lt;br /&gt;&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red128\green128\blue128;\red0\green128\blue0;\red43\green145\blue175;\red163\green21\blue21;}??\fs20   \cf3 namespace\cf0  CustomFxCopRules\par ??  \{\par ??      \cf4 ///\cf5  \cf4 &amp;lt;summary&amp;gt;\par ??\cf0       \cf4 ///\cf5  Warns of any methods being called that are removed from non-debug builds,\par ??\cf0       \cf4 ///\cf5  such as Debug.WriteLine()\par ??\cf0       \cf4 ///\cf5  \cf4 &amp;lt;/summary&amp;gt;\par ??\cf0       \cf3 public\cf0  \cf3 class\cf0  \cf6 DoNotCallDebugConditionalMethods\cf0  : \cf6 BaseIntrospectionRule\par ??\cf0       \{\par ??          \cf3 public\cf0  DoNotCallDebugConditionalMethods()\par ??              : \cf3 base\cf0 (\cf7 "DoNotCallDebugConditionalMethods"\cf0 , \cf7 "CustomFxCopRules.rules.xml"\cf0 ,\par ??                  \cf3 typeof\cf0 (\cf6 DoNotCallDebugConditionalMethods\cf0 ).Assembly)\par ??          \{ \}\par ??\par ??          \cf3 public\cf0  \cf3 override\cf0  \cf6 ProblemCollection\cf0  Check(\cf6 Member\cf0  member)\par ??          \{\par ??              \cf6 Method\cf0  method = member \cf3 as\cf0  \cf6 Method\cf0 ;\par ??              \cf3 if\cf0  (method != \cf3 null\cf0 )\par ??              \{\par ??                  VisitStatements(method.Body.Statements);\par ??              \}\par ??\par ??              \cf3 return\cf0  Problems;\par ??          \}\par ??\par ??          \cf3 public\cf0  \cf3 override\cf0  \cf3 void\cf0  VisitMethodCall(\cf6 MethodCall\cf0  call)\par ??          \{\par ??              \cf3 var\cf0  member = ((\cf6 MemberBinding\cf0 )call.Callee).BoundMember;\par ??              \cf3 var\cf0  method = (\cf6 Method\cf0 )member;\par ??              \cf3 var\cf0  symbol = method.ConditionalSymbol;\par ??\par ??              \cf3 if\cf0  (!\cf3 string\cf0 .IsNullOrEmpty(symbol) &amp;amp;&amp;amp; symbol.Contains(\cf7 "DEBUG"\cf0 ))\par ??              \{\par ??                  Problems.Add(\cf3 new\cf0  \cf6 Problem\cf0 (GetResolution(method.FullName), call.SourceContext));\par ??              \}\par ??          \}\par ??      \}\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;namespace&lt;/span&gt; CustomFxCopRules&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;span style="color: gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; Warns of any methods being called that are removed from non-debug builds,&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; such as Debug.WriteLine()&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;span style="color: gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;DoNotCallDebugConditionalMethods&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;BaseIntrospectionRule&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; DoNotCallDebugConditionalMethods()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; : &lt;span style="color: blue;"&gt;base&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"DoNotCallDebugConditionalMethods"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"CustomFxCopRules.rules.xml"&lt;/span&gt;,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;DoNotCallDebugConditionalMethods&lt;/span&gt;).Assembly)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; { }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;override&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;ProblemCollection&lt;/span&gt; Check(&lt;span style="color: #2b91af;"&gt;Member&lt;/span&gt; member)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: #2b91af;"&gt;Method&lt;/span&gt; method = member &lt;span style="color: blue;"&gt;as&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Method&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (method != &lt;span style="color: blue;"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; VisitStatements(method.Body.Statements);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; Problems;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;override&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; VisitMethodCall(&lt;span style="color: #2b91af;"&gt;MethodCall&lt;/span&gt; call)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; member = ((&lt;span style="color: #2b91af;"&gt;MemberBinding&lt;/span&gt;)call.Callee).BoundMember;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; method = (&lt;span style="color: #2b91af;"&gt;Method&lt;/span&gt;)member;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;var&lt;/span&gt; symbol = method.ConditionalSymbol;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (!&lt;span style="color: blue;"&gt;string&lt;/span&gt;.IsNullOrEmpty(symbol) &amp;amp;&amp;amp; symbol.Contains(&lt;span style="color: #a31515;"&gt;"DEBUG"&lt;/span&gt;))&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; Problems.Add(&lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Problem&lt;/span&gt;(GetResolution(method.FullName), call.SourceContext));&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-2639062783565853665?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/2639062783565853665/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/07/custom-fxcop-rule-calling-debug-methods.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2639062783565853665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2639062783565853665'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/07/custom-fxcop-rule-calling-debug-methods.html' title='A custom FxCop rule - calling Debug methods'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-6961855502984163404</id><published>2010-06-25T10:30:00.000-05:00</published><updated>2010-06-25T10:30:02.257-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>In space, no one can hear you scream</title><content type='html'>Lately, most of my time is being spent refactoring legacy code.  Everywhere I look I find try/catch blocks wrapped around a few lines of code. It appears the developer was using this as a way to "fix" bugs - by catching and eating the exception instead of tracking down the root cause. Enabling &lt;a href="http://automaticchainsaw.blogspot.com/2007/07/debugging-with-exception-breakpoints.html" title="Debugging with Exception Breakpoints"&gt;exception breakpoints&lt;/a&gt; and attempting to run the code is enough to make a developer scream.  Unfortunately, if the exception isn't rethrown...&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red0\green128\blue0;}??\fs20    \cf3 catch\cf0  (\cf4 Exception\cf0 )\par ??   \{\par ??       \cf5 // No one can hear you scream!\par ??\cf0    \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;catch&lt;/span&gt; (&lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;span style="color: green;"&gt;// No one can hear you scream!&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;I may have to &lt;a href="http://www.cafepress.com/" title="CafePress"&gt;put that on a t-shirt...&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-6961855502984163404?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/6961855502984163404/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/06/in-space-no-one-can-hear-you-scream.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/6961855502984163404'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/6961855502984163404'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/06/in-space-no-one-can-hear-you-scream.html' title='In space, no one can hear you scream'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-3036741370041940791</id><published>2010-06-21T13:26:00.000-05:00</published><updated>2010-06-21T13:26:59.429-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FxCop'/><title type='text'>Proper exception usage</title><content type='html'>Continuing our FxCop &lt;a href="http://automaticchainsaw.blogspot.com/2010/02/fxcop-starting-point.html" title="FxCop: A starting point"&gt;code cleanup&lt;/a&gt;, I decided to focus the next set of rules on working with exceptions.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms182338(v=VS.100).aspx"&gt;Do not raise reserved exception types&lt;/a&gt;&lt;/u&gt;&lt;br /&gt;&lt;br /&gt;These exceptions (such as SystemException and OutOfMemoryException) were designed as base classes or for CLR use only. Instead of using one of these, either find a more specific one in the .Net Framework or create your own.&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red0\green128\blue0;\red43\green145\blue175;\red163\green21\blue21;}??\fs20   \cf3 public\cf0  \cf3 static\cf0  \cf3 void\cf0  ThrowsBaseException()\par ??  \{\par ??      \cf4 // This is too vague to be useful\par ??\cf0       \cf3 throw\cf0  \cf3 new\cf0  \cf5 Exception\cf0 (\cf6 "Bummer"\cf0 );\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; ThrowsBaseException()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: green;"&gt;// This is too vague to be useful&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"Bummer"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;u&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms182347(v=VS.100).aspx"&gt;Instantiate argument exceptions correctly&lt;/a&gt;&lt;/u&gt;&lt;br /&gt;&lt;br /&gt;The following is an example violation. Note that the thrown exception doesn't inform the caller which argument was at fault or how it was supposed to be called.&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;}??\fs20   \cf3 public\cf0  \cf3 static\cf0  \cf3 int\cf0  Divide(\cf3 int\cf0  dividend, \cf3 int\cf0  divisor)\par ??  \{\par ??      \cf3 if\cf0  (divisor == 0)\par ??          \cf3 throw\cf0  \cf3 new\cf0  \cf4 ArgumentException\cf0 ();\par ??\par ??      \cf3 return\cf0  dividend / divisor;\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; Divide(&lt;span style="color: blue;"&gt;int&lt;/span&gt; dividend, &lt;span style="color: blue;"&gt;int&lt;/span&gt; divisor)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (divisor == 0)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;ArgumentException&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; dividend / divisor;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;To fix this, use a constructor that takes the name of the parameter and/or a string message stating the problem.&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;}??\fs20   \cf3 throw\cf0  \cf3 new\cf0  \cf4 ArgumentException\cf0 (\cf5 "Divisor cannot be 0."\cf0 , \cf5 "divisor"\cf0 );}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;ArgumentException&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"Divisor cannot be 0"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"divisor"&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;u&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb386039(v=VS.100).aspx"&gt;Do not raise exceptions in unexpected locations&lt;/a&gt;&lt;/u&gt;&lt;br /&gt;&lt;br /&gt;Certain methods are generally assumed to never throw an exception when called (equality operators) or only throw certain exceptions (such as property getters.) To be consistent, your code should follow a similar pattern.&lt;br /&gt;&lt;br /&gt;For example, the debugger uses the ToString method to display information. The following will cause issues while debugging:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;}??\fs20   \cf3 public\cf0  \cf3 override\cf0  \cf3 string\cf0  ToString()\par ??  \{\par ??      \cf3 throw\cf0  \cf3 new\cf0  \cf4 Exception\cf0 (\cf5 "Don't do this!"\cf0 );\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;override&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; ToString()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"Don't do this!"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;u&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb386041(v=VS.100).aspx"&gt;Do not raise exceptions in exception clauses&lt;/a&gt;&lt;/u&gt;&lt;br /&gt;&lt;br /&gt;The following code attempts to call the Divide method with a divisor of zero:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;}??\fs20   \cf3 public\cf0  \cf3 void\cf0  ThrowsExceptionFromFinally()\par ??  \{\par ??      \cf3 try\par ??\cf0       \{\par ??          Divide(12, 0);\par ??      \}\par ??      \cf3 finally\par ??\cf0       \{\par ??          \cf3 throw\cf0  \cf3 new\cf0  \cf4 Exception\cf0 (\cf5 "Ouch"\cf0 );\par ??      \}\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; ThrowsExceptionFromFinally()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;try&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; Divide(12, 0);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;finally&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"Ouch"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Based on the method defined previously, the code should throw an ArgumentException. In this example, however, the ArgumentException is lost due to a new exception being thrown from the finally block. If you want to thrown a new exception, do so from a catch block and include the caught exception as the inner exception.&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;}??\fs20   \cf3 catch\cf0  (\cf4 ArgumentException\cf0  ex)\par ??  \{\par ??      \cf3 throw\cf0  \cf3 new\cf0  \cf4 Exception\cf0 (\cf5 "Ouch"\cf0 , ex);\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;catch&lt;/span&gt; (&lt;span style="color: #2b91af;"&gt;ArgumentException&lt;/span&gt; ex)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"Ouch"&lt;/span&gt;, ex);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;u&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb264484(v=VS.100).aspx"&gt;Exceptions should be public&lt;/a&gt;&lt;/u&gt;&lt;br /&gt;&lt;br /&gt;The previous rules dealt with exceptions built into the .Net Framework. The last two deal with custom exceptions. Take the following custom exception class:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;}??\fs20   \cf3 internal\cf0  \cf3 class\cf0  \cf4 MyCustomException\cf0  : \cf4 Exception\par ??\cf0   \{    \par ??      \cf3 public\cf0  MyCustomException()\par ??      \{            \par ??      \}\par ??  \par ??      \cf3 public\cf0  MyCustomException(\cf3 string\cf0  message)\par ??          : \cf3 base\cf0 (message)\par ??      \{            \par ??      \}\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;internal&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;MyCustomException&lt;/span&gt; : &lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; MyCustomException()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; MyCustomException(&lt;span style="color: blue;"&gt;string&lt;/span&gt; message)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; : &lt;span style="color: blue;"&gt;base&lt;/span&gt;(message)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Note that the class is marked internal. The problem with this is that outside the assembly, the only way to handle this exception is to catch the base Exception (&lt;a href="http://msdn.microsoft.com/en-us/library/ms182137.aspx" title="Do not catch general exception types"&gt;which is a bad thing&lt;/a&gt;.)  The simple fix is to make the class public.&lt;br /&gt;&lt;br /&gt;&lt;u&gt;&lt;a href=""&gt;Implement standard exception constructors&lt;/a&gt;&lt;/u&gt;&lt;br /&gt;&lt;br /&gt;Using the above exception class, note there are currently two constructors.  The base Exception, however, defines two others - one to allow inner exceptions and one for serialization. Correcting the violation means making sure all four standard constructors have been defined.  To fix the above class, the following methods need to be added:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;}??\fs20   \cf3 public\cf0  MyCustomException(\cf3 string\cf0  message, \cf4 Exception\cf0  innerException)\par ??      : \cf3 base\cf0 (message, innerException)\par ??  \{            \par ??  \}\par ??  \cf3 protected\cf0  MyCustomException(\cf4 SerializationInfo\cf0  info, \cf4 StreamingContext\cf0  context)\par ??      : \cf3 base\cf0 (info, context)\par ??  \{            \par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; MyCustomException(&lt;span style="color: blue;"&gt;string&lt;/span&gt; message, &lt;span style="color: #2b91af;"&gt;Exception&lt;/span&gt; innerException)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; : &lt;span style="color: blue;"&gt;base&lt;/span&gt;(message, innerException)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;protected&lt;/span&gt; MyCustomException(&lt;span style="color: #2b91af;"&gt;SerializationInfo&lt;/span&gt; info, &lt;span style="color: #2b91af;"&gt;StreamingContext&lt;/span&gt; context)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; : &lt;span style="color: blue;"&gt;base&lt;/span&gt;(info, context)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-3036741370041940791?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/3036741370041940791/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/06/proper-exception-usage.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/3036741370041940791'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/3036741370041940791'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/06/proper-exception-usage.html' title='Proper exception usage'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-7094437798719279057</id><published>2010-05-14T09:29:00.002-05:00</published><updated>2010-05-14T09:38:18.813-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FxCop'/><title type='text'>Easy pickings: Class-level FxCop warnings</title><content type='html'>The &lt;a href="http://automaticchainsaw.blogspot.com/2010/03/remove-unused-code.html" title="Remove unused code"&gt;last batch&lt;/a&gt; of FxCop warnings proved to require a lot more effort than I had anticipated. It's amazing how much dead code accumulates over the years. For the next set of rules I decided to pick ones that were easy to fix but, more importantly, had few actual violations in our projects.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms182126.aspx"&gt;&lt;b&gt;Abstract types should not have constructors&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The following class violates the rule:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red0\green128\blue0;}??\fs20   \cf3 public\cf0  \cf3 abstract\cf0  \cf3 class\cf0  \cf4 MyAbstractClass\par ??\cf0   \{\par ??      \cf3 public\cf0  MyAbstractClass()\par ??      \{\par ??          \cf5 // Do setup code for derived classes\par ??\cf0       \}\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;abstract&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;MyAbstractClass&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; MyAbstractClass()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: green;"&gt;// Do setup code for derived classes&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;A class defined as abstract can't be instantiated directly. Thus, the only purpose for a constructor is to allow for default setup when a derived class is created.  To fix the issue, change the constructor accessibility to protected.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms182138.aspx"&gt;&lt;b&gt;Do not declare protected members in sealed types&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms182140.aspx"&gt;&lt;b&gt;Do not declare virtual members in sealed types&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;A sealed class is one that cannot be used as a base class. Protected and virtual members are useful for derived classes, which is a contradiction.  Fix the protected member by making it private instead.  As for the virtual members, this is a C++ issue only, as C# and VB.Net will fail to compile. To fix this for C++, unseal the class or remove the virtual modifier.&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red0\green128\blue0;}??\fs20   \cf3 public\cf0  \cf3 sealed\cf0  \cf3 class\cf0  \cf4 MySealedClass\par ??\cf0   \{\par ??      \cf3 protected\cf0  \cf3 void\cf0  Process()\par ??      \{\par ??          \cf5 // Do something\par ??\cf0       \}\par ??\par ??      \cf3 public\cf0  \cf3 virtual\cf0  \cf3 void\cf0  WillNotCompile()\par ??      \{\par ??          \cf5 // Appears to be a C++ feature only, so that was easy :)\par ??\cf0       \}\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;sealed&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;MySealedClass&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;protected&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Process()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: green;"&gt;// Might as well be private&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;virtual&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; WillNotCompile()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: green;"&gt;// A C++ feature only, so that was easy :)&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms182168.aspx"&gt;&lt;b&gt;Static holder types should be sealed&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms182169.aspx"&gt;&lt;b&gt;Static holder types should not have constructors&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Take the following:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red0\green128\blue0;}??\fs20   \cf3 public\cf0  \cf3 class\cf0  \cf4 MyStaticClass\par ??\cf0   \{\par ??      \cf3 public\cf0  \cf3 static\cf0  \cf3 void\cf0  DoWork()\par ??      \{\par ??          \cf5 // Do stuff here...\par ??\cf0       \}\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;MyStaticClass&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; DoWork()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: green;"&gt;// Do stuff here...&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;This class only contains static members, so there is no reason to create instances of the class.  When this is compiled, however, the class will be given a default public constructor.  Prior to .Net 2.0, the fix was to implement an empty constructor and set the access level to private.  Beginning with .Net 2.0, an easier fix is to set the class itself to static.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-7094437798719279057?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/7094437798719279057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/05/easy-pickings-class-level-fxcop.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7094437798719279057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7094437798719279057'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/05/easy-pickings-class-level-fxcop.html' title='Easy pickings: Class-level FxCop warnings'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-789255949583179902</id><published>2010-04-19T13:49:00.000-05:00</published><updated>2010-04-19T13:49:00.101-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='NUnit'/><title type='text'>Unit test all enum values with NUnit</title><content type='html'>In an &lt;a href="http://automaticchainsaw.blogspot.com/2009/08/parameterized-tests-in-nunit.html" title="Parameterized tests in NUnit"&gt;older post&lt;/a&gt; I demonstrated NUnit's built-in parameterized tests feature. This allows a developer to call a single method to run multiple tests.&lt;br /&gt;&lt;br /&gt;Let's say I want to run the test for each value in an enumeration. Using the TestCase attribute, I can write the test like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="background: white; color: black; font-family: Courier New; font-size: 10pt;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;TestCase&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;Powertools&lt;/span&gt;.Chainsaw)]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;TestCase&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;Powertools&lt;/span&gt;.CircularSaw)]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;TestCase&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;Powertools&lt;/span&gt;.PowerDrill)]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; PowerToolsTestExplicit(&lt;span style="color: #2b91af;"&gt;Powertools&lt;/span&gt; p)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: green;"&gt;// Do test&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Which is fine, but what if I add a new value to the enum?  Instead of having to add another attribute to the test, it would be easier to loop over all enum values at runtime.  With the &lt;a href="http://nunit.org/index.php?p=testCaseSource&amp;amp;r=2.5" title="TestCaseSource"&gt;TestCaseSource&lt;/a&gt; attribute I can do just that.&lt;br /&gt;&lt;br /&gt;Within my unit test class I first create a method that returns an IEnumerable (in this case Array) containing the enum values:&lt;br /&gt;&lt;br /&gt;&lt;div style="background: white; color: black; font-family: Courier New; font-size: 10pt;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Array&lt;/span&gt; GetPowerTools()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Enum&lt;/span&gt;.GetValues(&lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af;"&gt;Powertools&lt;/span&gt;));&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Then I create my unit test and decorate it with the TestCaseSource attribute. The attribute constructor takes one parameter, sourceName, which is the name of the method to call:&lt;br /&gt;&lt;br /&gt;&lt;div style="background: white; color: black; font-family: Courier New; font-size: 10pt;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; [&lt;span style="color: #2b91af;"&gt;TestCaseSource&lt;/span&gt;(&lt;span style="color: #a31515;"&gt;"GetPowerTools"&lt;/span&gt;)]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; PowerToolsTestWithIEnumerable(&lt;span style="color: #2b91af;"&gt;Powertools&lt;/span&gt; p)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: green;"&gt;// Do test&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;In either case, this expands my unit tests as expected. The second method is easier to maintain and less likely to allow untested code into the system.&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/_nWyC8gWd544/S8yiqOqihFI/AAAAAAAAAVU/lcznh91mQI0/s1600/unit_tests.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_nWyC8gWd544/S8yiqOqihFI/AAAAAAAAAVU/lcznh91mQI0/s320/unit_tests.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-789255949583179902?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/789255949583179902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/04/unit-test-all-enum-values-with-nunit.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/789255949583179902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/789255949583179902'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/04/unit-test-all-enum-values-with-nunit.html' title='Unit test all enum values with NUnit'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nWyC8gWd544/S8yiqOqihFI/AAAAAAAAAVU/lcznh91mQI0/s72-c/unit_tests.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-8626123059854507951</id><published>2010-03-29T16:34:00.000-05:00</published><updated>2010-03-29T16:34:36.972-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FxCop'/><title type='text'>Remove unused code</title><content type='html'>When considering the next set of FxCop rules to enable on the build server, my first thought was to look at those dealing with properly disposing of objects. Scanning the active projects at work has revealed a rule-set slightly more important - unused code.  In some of our older code bases there are a variety of methods, variables, etc. that are no longer being used. Deleting the dead code will make it easier to understand what the code is actually doing. In many cases, this will also fix a variety of other FxCop issues, as the flagged items are no longer present.  Why fix what you will eventually delete?&lt;br /&gt;&lt;br /&gt;And before I go over the rules I should emphasize &lt;b&gt;deletion&lt;/b&gt; of dead code. I've seen numerous instances where a developer has commented out, #ifdef'd, or otherwise excluded a section of code.  In some cases this was to finish or re-implement the code later. In other cases it was to remove code not currently needed. Regardless, this should be avoided. Tracking previous revisions of code is what source control is for.&lt;br /&gt;&lt;br /&gt;The first rule to address is &lt;a href="http://msdn.microsoft.com/en-us/library/ms182265.aspx" title="Avoid uninstantiated internal classes"&gt;Avoid uninstantiated internal classes&lt;/a&gt;. This is a class not visible outside the assembly and is never actually used within that assembly. If you're lucky, deleting this class will improve a variety of code metrics (the number of FxCop warnings being just one of them.)&lt;br /&gt;&lt;br /&gt;For the next examples I reference the following class:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red43\green145\blue175;\red163\green21\blue21;}??\fs20   \cf3 public\cf0  \cf3 class\cf0  \cf4 Unused\par ??\cf0   \{\par ??      \cf3 int\cf0  unusedPrivateField;\par ??\par ??      \cf3 private\cf0  \cf3 void\cf0  UnusedPrivateCode()\par ??      \{\par ??          \cf4 Debug\cf0 .WriteLine(\cf5 "This method isn't called"\cf0 );\par ??      \}\par ??\par ??      \cf3 internal\cf0  \cf3 void\cf0  DoWork()\par ??      \{\par ??          \cf3 int\cf0  unusedLocal;\par ??          \cf4 Debug\cf0 .WriteLine(\cf5 "This is the only method possibly called"\cf0 );\par ??      \}\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;9&lt;/span&gt;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;Unused&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;10&lt;/span&gt;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;11&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;int&lt;/span&gt; unusedPrivateField;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;12&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;13&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; UnusedPrivateCode()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;14&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;15&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: #2b91af;"&gt;Debug&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515;"&gt;"This method isn't called"&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;16&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;17&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;18&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;internal&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; DoWork()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;19&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;20&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;int&lt;/span&gt; unusedLocal;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;21&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: #2b91af;"&gt;Debug&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515;"&gt;"This is the only method possibly called"&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;22&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;23&lt;/span&gt;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;Working through the code, line 11 returns a warning for the rule &lt;a href = "http://msdn.microsoft.com/en-us/library/ms245042.aspx" title="Avoid unused private fields"&gt;Avoid unused private fields&lt;/a&gt;.  Notice that none of the methods use it and it isn't exposed through a property.&lt;br /&gt;&lt;br /&gt;Next, the method UnusedPrivateCode violates, you guessed it, &lt;a href="http://msdn.microsoft.com/en-us/library/ms182264.aspx" title="Avoid uncalled private code"&gt;Avoid uncalled private code&lt;/a&gt;. This method is uncalled locally and unreachable outside the class.&lt;br /&gt;&lt;br /&gt;The final violation is of type &lt;a href="http://msdn.microsoft.com/en-us/library/ms182278.aspx" title="Remove unused locals"&gt;Remove unused locals&lt;/a&gt;, at line 20.  The variable is not used within the method and can be removed.  Note that this rule will also fire if the variable is assigned to, but its value is never actually used.  An example:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red0\green128\blue0;}??\fs20   \cf3 public\cf0  \cf3 void\cf0  DoWork()\par ??  \{\par ??      \cf3 int\cf0  unusedLocal = 0;\par ??      unusedLocal = 12; \cf4 // Still not using...\par ??\cf0   \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;18&lt;/span&gt;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; DoWork()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;19&lt;/span&gt;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;20&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;int&lt;/span&gt; unusedLocal = 0;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;21&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; unusedLocal = 12; &lt;span style="color: green;"&gt;// Still not using...&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;22&lt;/span&gt;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-8626123059854507951?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/8626123059854507951/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/03/remove-unused-code.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8626123059854507951'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8626123059854507951'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/03/remove-unused-code.html' title='Remove unused code'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-5521264839459907894</id><published>2010-03-04T23:20:00.002-06:00</published><updated>2010-03-04T23:25:21.374-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FxCop'/><title type='text'>Rethrowing exceptions to preserve stack details</title><content type='html'>In my &lt;a href="http://automaticchainsaw.blogspot.com/2010/02/fxcop-starting-point.html" title="FxCop: A starting point"&gt;last post&lt;/a&gt;, I described our plan at work to introduce FxCop into our development process. The first rule we will be enforcing is &lt;a href="http://msdn.microsoft.com/en-us/library/ms182363.aspx" title="Rethrow to preserve stack details"&gt;RethrowToPreserveStackDetails&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The following example violates the rule:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20   \cf2 public\cf0  \cf2 void\cf0  MyTest()\par ??  \{\par ??      Process();\par ??  \}\par ??\par ??  \cf2 public\cf0  \cf2 void\cf0  Process()\par ??  \{\par ??      \cf2 try\par ??\cf0       \{\par ??          \cf2 int\cf0  result = \cf10 Calculator\cf0 .Divide(12, 0);\par ??      \}\par ??      \cf2 catch\cf0  (\cf10 DivideByZeroException\cf0  ex)\par ??      \{\par ??          \cf11 // React, likely by logging\par ??\cf0           \cf2 throw\cf0  ex; \cf11 // &amp;lt;- This is wrong\par ??\cf0       \}\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;12&lt;/span&gt;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; MyTest()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;13&lt;/span&gt;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;14&lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; Process();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;15&lt;/span&gt;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;16&lt;/span&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;17&lt;/span&gt;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; Process()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;18&lt;/span&gt;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;19&lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;try&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;20&lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;21&lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;int&lt;/span&gt; result = &lt;span style="color: teal;"&gt;Calculator&lt;/span&gt;.Divide(12, 0);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;22&lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;23&lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;catch&lt;/span&gt; (&lt;span style="color: teal;"&gt;DivideByZeroException&lt;/span&gt; ex)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;24&lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;25&lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: green;"&gt;// React, likely by logging&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;26&lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;throw&lt;/span&gt; ex; &lt;span style="color: green;"&gt;// &amp;lt;- This is wrong&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;27&lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;28&lt;/span&gt;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Executing this code results in the following logged callstack&lt;br /&gt;&lt;pre&gt;&lt;i&gt;  ...FxCopTests.Process() in C:\test\FxCopTests.cs:line 26&lt;br /&gt;  ...FxCopTests.MyTest() in C:\test\FxCopTests.cs:line 14&lt;br /&gt;&lt;/i&gt;&lt;/pre&gt;Note that the callstack ends with line 26, which is in the catch block. In this example the real exception location isn't hard to find. Unfortunately, production code is rarely this simple.&lt;br /&gt;&lt;br /&gt;The problem here is that calling "throw ex" causes the callstack info to be created at that point. If you were creating a new exception and throwing it this would be desired behavior. With an existing exception you don't want the original callstack to be overwritten.&lt;br /&gt;&lt;br /&gt;The fix for this code is easy enough - replace:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20   \cf2 throw\cf0  ex;}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;throw&lt;/span&gt; ex;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;with&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20   \cf2 throw\cf0 ;}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;throw&lt;/span&gt;;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;After this change, the callstack correctly points to the line throwing the exception&lt;br /&gt;&lt;pre&gt;&lt;i&gt;&lt;b&gt;  ...Calculator.Divide(Int32 x, Int32 y) in C:\test\Calculator.cs:line 11&lt;/b&gt;&lt;br /&gt;  ...FxCopTests.Process() in C:\test\FxCopTests.cs:line 26&lt;br /&gt;  ...FxCopTests.MyTest() in C:\test\FxCopTests.cs:line 14&lt;/i&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-5521264839459907894?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/5521264839459907894/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/03/rethrowing-exceptions-to-preserve-stack.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/5521264839459907894'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/5521264839459907894'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/03/rethrowing-exceptions-to-preserve-stack.html' title='Rethrowing exceptions to preserve stack details'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-7405741232264505942</id><published>2010-02-16T19:33:00.001-06:00</published><updated>2010-04-14T13:29:35.230-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FxCop'/><title type='text'>FxCop: A starting point</title><content type='html'>In an effort to improve overall code quality at work, we are initiating manual and automated code reviews. One of the tools we will be using for automated reviews is &lt;a href="http://msdn.microsoft.com/en-us/library/bb429476(VS.80).aspx" title="FxCop "&gt;FxCop&lt;/a&gt;. There are just two minor issues with this:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Running every rule on an existing code base usually results in a massive &lt;a href="http://msmvps.com/blogs/calinoiu/archive/2007/04/22/fxcop-and-the-big-bad-backlog.aspx" title="FxCop and the big, bad backlog"&gt;backlog&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Most developers, myself included, are unfamiliar with at least some of the rules&lt;/li&gt;&lt;/ol&gt;Granted, several of the rules categories can be turned off on most projects (Portability and Interoperability come to mind.) There are also a few rules that are unimportant or largely &lt;a href="http://msmvps.com/blogs/calinoiu/archive/2010/02/03/what-s-wrong-with-the-net-design-guidelines-dispose-bool-disposing.aspx" title="Dispose(ohNotThisNonsenseYetAgain)"&gt;obsolete&lt;/a&gt;. This still leaves a sizeable list of rules to deal with.&lt;br /&gt;&lt;br /&gt;Our planned approach is to enable several of the rules as warnings on the build server. After the developers have addressed any issues, the build will be modified to fail on future violations of those rules. Slowly adding rules, first as warnings and then as errors, will allow us to clean up our existing code base and prevent new violations from being introduced. As we go I will be putting together examples of violations and fixes. I'll post the examples for those who want to follow along at home.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-7405741232264505942?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/7405741232264505942/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/02/fxcop-starting-point.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7405741232264505942'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7405741232264505942'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2010/02/fxcop-starting-point.html' title='FxCop: A starting point'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-2500047775212798419</id><published>2009-11-13T16:41:00.000-06:00</published><updated>2009-11-13T16:41:58.635-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='refactoring'/><title type='text'>More than one way to sort a List&lt;&gt;</title><content type='html'>One operation you occasionally need to perform is sorting a generic list of objects. Often developers code handle with an inline delegate.  If I wanted to sort a collection of boardgames by rating, my code might look like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="-moz-background-clip: -moz-initial; -moz-background-inline-policy: -moz-initial; -moz-background-origin: -moz-initial; background: white none repeat scroll 0% 0%; color: black; font-family: Courier New; font-size: 10pt;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; games.Sort(&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;delegate&lt;/span&gt;(&lt;span style="color: teal;"&gt;BoardGame&lt;/span&gt; a, &lt;span style="color: teal;"&gt;BoardGame&lt;/span&gt; b)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (a.Rating &amp;lt; b.Rating)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; 1;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (a.Rating &amp;gt; b.Rating)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; -1;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; 0;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; });&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Although this works, it tends to look a bit cluttered.  It also increases a method's complexity and doesn't adhere to the idea of &lt;a href="http://en.wikipedia.org/wiki/Separation_of_concerns" title="Separation of concerns"&gt;separation of concerns&lt;/a&gt;. If we only need to sort Boardgames in this one location, a better solution is to move the comparison code into a separate method in the same class. The new method looks like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="-moz-background-clip: -moz-initial; -moz-background-inline-policy: -moz-initial; -moz-background-origin: -moz-initial; background: white none repeat scroll 0% 0%; color: black; font-family: Courier New; font-size: 10pt;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; CompareBoardgamesByRank(&lt;span style="color: teal;"&gt;BoardGame&lt;/span&gt; a, &lt;span style="color: teal;"&gt;BoardGame&lt;/span&gt; b)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (a.Rating &amp;lt; b.Rating)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; 1;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (a.Rating &amp;gt; b.Rating)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; -1;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; 0;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Our call to Sort looks like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="-moz-background-clip: -moz-initial; -moz-background-inline-policy: -moz-initial; -moz-background-origin: -moz-initial; background: white none repeat scroll 0% 0%; color: black; font-family: Courier New; font-size: 10pt;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; games.Sort(CompareBoardgamesByRank);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;This makes the code much cleaner for a single sort.  If we want to sort Boardgames by rating from multiple locations, we need a better place to store the comparison method. If we implement IComparable on our Boardgame class, we can create a CompareTo method on the class like so:&lt;br /&gt;&lt;br /&gt;&lt;div style="-moz-background-clip: -moz-initial; -moz-background-inline-policy: -moz-initial; -moz-background-origin: -moz-initial; background: white none repeat scroll 0% 0%; color: black; font-family: Courier New; font-size: 10pt;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; CompareTo(&lt;span style="color: blue;"&gt;object&lt;/span&gt; obj)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: teal;"&gt;BoardGame&lt;/span&gt; b = (&lt;span style="color: teal;"&gt;BoardGame&lt;/span&gt;)obj;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (Rating &amp;lt; b.Rating)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; 1;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (Rating &amp;gt; b.Rating)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; -1;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; 0;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Since the class now has a default comparison, we no longer need to specify a delegate when calling Sort - the CompareTo method will automatically be executed with an empty call:&lt;br /&gt;&lt;br /&gt;&lt;div style="-moz-background-clip: -moz-initial; -moz-background-inline-policy: -moz-initial; -moz-background-origin: -moz-initial; background: white none repeat scroll 0% 0%; color: black; font-family: Courier New; font-size: 10pt;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; games.Sort();&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;What if we need additional comparison methods for our Boardgame? An easy way to handle this is to create static methods on the class, which will be available anywhere that Boardgame can be accessed. Here are a couple methods I've added to my Boardgame class:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20   \cf2 public\cf0  \cf2 static\cf0  \cf2 int\cf0  CompareByName(\cf10 BoardGame\cf0  a, \cf10 BoardGame\cf0  b)\par ??  \{\par ??      \cf2 return\cf0  \cf2 string\cf0 .Compare(a.Name, b.Name);\par ??  \}\par ??\par ??  \cf2 public\cf0  \cf2 static\cf0  \cf2 int\cf0  CompareByRankAssending(\cf10 BoardGame\cf0  a, \cf10 BoardGame\cf0  b)\par ??  \{\par ??      \cf2 if\cf0  (a.Rating &amp;gt; b.Rating)\par ??          \cf2 return\cf0  1;\par ??      \cf2 if\cf0  (a.Rating &amp;lt; b.Rating)\par ??          \cf2 return\cf0  -1;\par ??      \cf2 return\cf0  0;\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; CompareByName(&lt;span style="color: teal;"&gt;BoardGame&lt;/span&gt; a, &lt;span style="color: teal;"&gt;BoardGame&lt;/span&gt; b)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt;.Compare(a.Name, b.Name);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;int&lt;/span&gt; CompareByRankAssending(&lt;span style="color: teal;"&gt;BoardGame&lt;/span&gt; a, &lt;span style="color: teal;"&gt;BoardGame&lt;/span&gt; b)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (a.Rating &amp;gt; b.Rating)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; 1;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (a.Rating &amp;lt; b.Rating)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; -1;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; 0;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Which I can now pass into the Sort method:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20   games.Sort(\cf10 BoardGame\cf0 .CompareByRankAssending);}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; games.Sort(&lt;span style="color: teal;"&gt;BoardGame&lt;/span&gt;.CompareByRankAssending);&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-2500047775212798419?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/2500047775212798419/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/11/more-than-one-way-to-sort-list.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2500047775212798419'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2500047775212798419'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/11/more-than-one-way-to-sort-list.html' title='More than one way to sort a List&lt;&gt;'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-5622891998278742026</id><published>2009-10-20T17:31:00.000-05:00</published><updated>2009-10-20T17:31:27.007-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='refactoring'/><title type='text'>Refactoring assemblies without breaking existing apps</title><content type='html'>Over time, most development shops identify common code that needs to be used across multiple projects. This code is eventually collected into a single assembly, usually something like Common.dll or Utilities.dll.  In the beginning this is a decent way to eliminate code duplication.  Over time, however, this single assembly becomes difficult to maintain.&lt;br /&gt;&lt;br /&gt;At this point the obvious fix is to split the assembly into multiple smaller ones.  Unfortunately, by then the single assembly is used on numerous projects.  A major refactoring now requires extensive changes across all of these referencing applications.  This realization usually stops any refactoring effort, leaving the utilities assembly to continue growing larger and more unwieldy.&lt;br /&gt;&lt;br /&gt;To look at potential solutions, I've created a Utilities assembly with the following Logger class:&lt;br /&gt;&lt;br /&gt;&lt;div style="-moz-background-clip: -moz-initial; -moz-background-inline-policy: -moz-initial; -moz-background-origin: -moz-initial; background: white none repeat scroll 0% 0%; color: black; font-family: Courier New; font-size: 10pt;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;namespace&lt;/span&gt; Utilities&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: teal;"&gt;Logger&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; LogError(&lt;span style="color: blue;"&gt;string&lt;/span&gt; message)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: teal;"&gt;Debug&lt;/span&gt;.WriteLine(&lt;span style="color: maroon;"&gt;"Error:&amp;nbsp;"&lt;/span&gt; + message);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;The goal is to move this class to a separate assembly called LoggingUtilities.&lt;br /&gt;&lt;br /&gt;One solution is to use the TypeForwardedTo attribute.  This is an assembly-level attribute that flags a specified class as having moved. To use this, I start by moving the Logger class to my new assembly. Note that I keep the same namespace as before - this is required for the forwarding to work.&lt;br /&gt;&lt;br /&gt;Next I add a reference to LoggingUtilities within Utilities.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_nWyC8gWd544/St44ExH3i2I/AAAAAAAAAVI/UBObH0J83uU/s1600-h/AddedReference.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_nWyC8gWd544/St44ExH3i2I/AAAAAAAAAVI/UBObH0J83uU/s320/AddedReference.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Finally, I open up AssemblyInfo.cs file in the Utilities project and add the following line:&lt;br /&gt;&lt;br /&gt;&lt;div style="-moz-background-clip: -moz-initial; -moz-background-inline-policy: -moz-initial; -moz-background-origin: -moz-initial; background: white none repeat scroll 0% 0%; color: black; font-family: Courier New; font-size: 10pt;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; [assembly: &lt;span style="color: teal;"&gt;TypeForwardedTo&lt;/span&gt;(&lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(Utilities.&lt;span style="color: teal;"&gt;Logger&lt;/span&gt;))]&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;If I recompile the dlls and drop them in a folder with my existing application, it will continue to function even though the class has been moved.&lt;br /&gt;&lt;br /&gt;This takes care of keeping the current compiled code running, but what about future versions? If I open up the source for one of my applications and attempt to compile, I now receive errors stating "The type or namespace name 'Logger' could not be found." It seems the redirection works at runtime but not at compile time. For someone not familiar with the previous refactoring, this could prove an interesting issue to track down.&lt;br /&gt;&lt;br /&gt;In my opinion, there is a far better solution than using the TypeForwardedTo attribute.  Going back to the original code, this time I copy the code to the new assembly (as opposed to moving it.) On the copy I change the namespace to match my new assembly.&lt;br /&gt;&lt;br /&gt;&lt;div style="-moz-background-clip: -moz-initial; -moz-background-inline-policy: -moz-initial; -moz-background-origin: -moz-initial; background: white none repeat scroll 0% 0%; color: black; font-family: Courier New; font-size: 10pt;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;namespace&lt;/span&gt; LoggingUtilities&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: teal;"&gt;Logger&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; LogError(&lt;span style="color: blue;"&gt;string&lt;/span&gt; message)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; { &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: teal;"&gt;Debug&lt;/span&gt;.WriteLine(&lt;span style="color: maroon;"&gt;"Error: "&lt;/span&gt; + message);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;In my original Logger class, I create an instance of my new Logger. Each method in the original class now forwards requests to the new Logger instance.  In this way, I am wrapping the new class in the original.  This allows applications to still use the old class, though the functionality has been moved.&lt;br /&gt;&lt;br /&gt;&lt;div style="-moz-background-clip: -moz-initial; -moz-background-inline-policy: -moz-initial; -moz-background-origin: -moz-initial; background: white none repeat scroll 0% 0%; color: black; font-family: Courier New; font-size: 10pt;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: teal;"&gt;Logger&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; LoggingUtilities.&lt;span style="color: teal;"&gt;Logger&lt;/span&gt; _logger =&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;new&lt;/span&gt; LoggingUtilities.&lt;span style="color: teal;"&gt;Logger&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; [&lt;span style="color: teal;"&gt;Obsolete&lt;/span&gt;(&lt;span style="color: maroon;"&gt;"Use LoggingUtilities.Logger instead"&lt;/span&gt;)]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; LogError(&lt;span style="color: blue;"&gt;string&lt;/span&gt; message)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; _logger.LogError(message);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;As before we need to evaluate referencing projects. Because our original class still exists, these applications will continue to compile.  &lt;br /&gt;&lt;br /&gt;Note that I've added an "Obsolete" attribute to the LogError method.  This means we will receive a compiler warning (&lt;a href="http://automaticchainsaw.blogspot.com/2007/12/treat-warnings-as-errors.html" title="Treat Warnings as Errors"&gt;or error&lt;/a&gt;) that we need to change our application to use the new class.  This makes it clear what needs to be modified, saving time on any rework.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-5622891998278742026?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/5622891998278742026/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/10/refactoring-assemblies-without-breaking.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/5622891998278742026'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/5622891998278742026'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/10/refactoring-assemblies-without-breaking.html' title='Refactoring assemblies without breaking existing apps'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_nWyC8gWd544/St44ExH3i2I/AAAAAAAAAVI/UBObH0J83uU/s72-c/AddedReference.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-1116277606663639469</id><published>2009-10-18T13:21:00.002-05:00</published><updated>2009-10-18T13:27:14.160-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Code can be both clean and efficient</title><content type='html'>Chapter 26 of &lt;a href="http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670"&gt;Code Complete&lt;/a&gt; focuses on code tuning - the art of modifying code to improve performance. One example given is a switched loop:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20   \cf2 for\cf0  (i = 0; i &amp;lt; count; i++)\par ??  \{\par ??      \cf2 if\cf0  (sumType == SUMTYPE_NET)\par ??      \{\par ??          netSum = netSum + amount[i];\par ??      \}\par ??      \cf2 else\par ??\cf0       \{\par ??          grossSum = grossSum + amount[i];\par ??      \}\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;for&lt;/span&gt; (i = 0; i &amp;lt; count; i++)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (sumType == SUMTYPE_NET)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; netSum = netSum + amount[i];&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; grossSum = grossSum + amount[i];&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Notice the 'if' statement inside the loop. If the array is rather large, this statement will be evaluate numerous times, despite the fact that the result will never change. The recommended solution is to unswitch the loop, so the 'if' statement is only evaluated once:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20   \cf2 if\cf0  (sumType == SUMTYPE_NET)\par ??  \{\par ??      \cf2 for\cf0  (i = 0; i &amp;lt; count; i++)\par ??      \{\par ??          netSum = netSum + amount[i];\par ??      \}\par ??  \}\par ??  \cf2 else\par ??\cf0   \{\par ??      \cf2 for\cf0  (i = 0; i &amp;lt; count; i++)\par ??      \{\par ??          grossSum = grossSum + amount[i];\par ??      \}\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (sumType == SUMTYPE_NET)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;for&lt;/span&gt; (i = 0; i &amp;lt; count; i++)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; netSum = netSum + amount[i];&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;for&lt;/span&gt; (i = 0; i &amp;lt; count; i++)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; grossSum = grossSum + amount[i];&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;This recommendation was given with one warning: this code is harder to maintain. If the logic for the loops needs to change, you have to make sure to change both loops to match.&lt;br /&gt;&lt;br /&gt;As with most coding tasks, there is more than one possible solution. In this case the ideal approach is to have both a single comparison and a single loop.  If we throw one additional variable into the code, we can calculate the summation and then add it accordingly:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20   \cf2 for\cf0  (i = 0; i &amp;lt; count; i++)\par ??  \{\par ??      arraySum = arraySum + amount[i];\par ??  \}\par ??\par ??  \cf2 if\cf0  (sumType == SUMTYPE_NET)\par ??  \{\par ??      netSum = netSum + arraySum;\par ??  \}\par ??  \cf2 else\par ??\cf0   \{\par ??      grossSum = grossSum + arraySum;\par ??  \}\par ??}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;for&lt;/span&gt; (i = 0; i &amp;lt; count; i++)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; arraySum = arraySum + amount[i];&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;if&lt;/span&gt; (sumType == SUMTYPE_NET)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; netSum = netSum + arraySum;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; grossSum = grossSum + arraySum;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-1116277606663639469?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/1116277606663639469/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/10/code-can-be-both-clean-and-efficient.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1116277606663639469'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1116277606663639469'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/10/code-can-be-both-clean-and-efficient.html' title='Code can be both clean and efficient'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-2784683620023412731</id><published>2009-10-17T22:18:00.001-05:00</published><updated>2009-10-17T22:20:52.801-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MSAccess'/><title type='text'>Export filtered Access data to Excel</title><content type='html'>In my free time I've been creating an MSAccess database containing a few data-entry forms.  One of these forms allows the user to filter records based on several different criteria.  This part was relatively straightforward.  The difficulty was in trying to export the filtered information to an Excel spreadsheet.  Although this functionality exists in Access, the installed help file was less than helpful.  Forum posts seemed to contain partial solutions or solve something almost, but not quite what I was trying to do.&lt;br /&gt;&lt;br /&gt;The following VBA subroutine is the eventual solution:&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;Private&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt; Export_Click()&lt;br /&gt;    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; whereClause &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class="rem"&gt;' Generate our WHERE clause based on form values&lt;/span&gt;&lt;br /&gt;    whereClause = GenerateFilterClause&lt;br /&gt;    &lt;br /&gt;    &lt;span class="rem"&gt;' If we have no filter, export nothing&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;If&lt;/span&gt; IsEmptyString(Nz(whereClause)) &lt;span class="kwrd"&gt;Then&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;Exit&lt;/span&gt; &lt;span class="kwrd"&gt;Sub&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;End&lt;/span&gt; &lt;span class="kwrd"&gt;If&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; query &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt;&lt;br /&gt;    query = &lt;span class="str"&gt;"SELECT DISTINCTROW Contacts.* "&lt;/span&gt; &amp;amp; _&lt;br /&gt;            &lt;span class="str"&gt;" FROM Contacts "&lt;/span&gt; &amp;amp; _&lt;br /&gt;            &lt;span class="str"&gt;" INNER JOIN Applications "&lt;/span&gt; &amp;amp; _&lt;br /&gt;            &lt;span class="str"&gt;" ON Contacts.ContactID = Applications.ContactID "&lt;/span&gt; &amp;amp; _&lt;br /&gt;            &lt;span class="str"&gt;" WHERE "&lt;/span&gt; &amp;amp; whereClause &amp;amp; &lt;span class="str"&gt;";"&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; filename &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt;&lt;br /&gt;    filename = &lt;span class="str"&gt;"c:\test.xls"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="rem"&gt;' Placeholder query already in the database&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;Dim&lt;/span&gt; queryName &lt;span class="kwrd"&gt;As&lt;/span&gt; &lt;span class="kwrd"&gt;String&lt;/span&gt;&lt;br /&gt;    queryName = &lt;span class="str"&gt;"FilterExportQuery"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="rem"&gt;' Update the placeholder with the created query&lt;/span&gt;&lt;br /&gt;    CurrentDb.QueryDefs(queryName).SQL = query&lt;br /&gt;&lt;br /&gt;    &lt;span class="rem"&gt;' Run the export&lt;/span&gt;&lt;br /&gt;    DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, queryName, filename&lt;br /&gt;&lt;span class="kwrd"&gt;End&lt;/span&gt; Sub&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-2784683620023412731?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/2784683620023412731/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/10/export-filtered-access-data-to-excel.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2784683620023412731'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2784683620023412731'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/10/export-filtered-access-data-to-excel.html' title='Export filtered Access data to Excel'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-2430826240729741387</id><published>2009-10-12T02:52:00.001-05:00</published><updated>2009-10-12T15:20:30.820-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>Monitoring log files in real time</title><content type='html'>Debugging Windows services, especially in a test or production environment, can be tricky. In many cases you won't have access to the box. You certainly won't have the ability to step through the code.&lt;br /&gt;&lt;br /&gt;Thus, you are usually forced to monitor log files, looking for an indication of where the problem occurred. The typical method is to start by opening the file in Notepad. Then, when you want to see more recent log entries, you close and reopen the file. This is mildly annoying when dealing with a single service. If your business workflow is split among multiple services, this becomes incredibly inefficient.&lt;br /&gt;&lt;br /&gt;An easier solution is to use a log monitor app such as &lt;a href="http://www.baremetalsoft.com/baretail/"&gt;BareTail&lt;/a&gt;. For this little demo I am using the free version of the tool.&lt;br /&gt;&lt;br /&gt;I have three separate services logging to files named "process1.log", "process2.log" and "process3.log."   To keep it simple I am only logging the RequestID for each received request. Here I have loaded all three logs into BareTail.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nWyC8gWd544/StONx35VfTI/AAAAAAAAAUo/Mc45oWd7EzE/s1600-h/NewSession.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 310px;" src="http://2.bp.blogspot.com/_nWyC8gWd544/StONx35VfTI/AAAAAAAAAUo/Mc45oWd7EzE/s400/NewSession.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5391809066850155826" /&gt;&lt;/a&gt;&lt;br /&gt;When I send a new request to the system it should update each log file. BareTail monitors the logs and displays any updates. In the screenshot below, note the new Request ID #2918891.  Note also that the document tabs for each file show a green arrow - this indicates an update was made.  &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_nWyC8gWd544/StON5RlUVFI/AAAAAAAAAUw/MswHr_UAYt0/s1600-h/SimpleUpdate.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 310px;" src="http://3.bp.blogspot.com/_nWyC8gWd544/StON5RlUVFI/AAAAAAAAAUw/MswHr_UAYt0/s400/SimpleUpdate.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5391809194004599890" /&gt;&lt;/a&gt;&lt;br /&gt;As you view each tab, the green arrow will be cleared to visually show which files you have already reviewed.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nWyC8gWd544/StOOAbyG47I/AAAAAAAAAU4/xjbI6UZ3nO0/s1600-h/View1and2.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 310px;" src="http://1.bp.blogspot.com/_nWyC8gWd544/StOOAbyG47I/AAAAAAAAAU4/xjbI6UZ3nO0/s400/View1and2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5391809317001683890" /&gt;&lt;/a&gt;&lt;br /&gt;Say you were trying to debug a request that fails to make it through the system. A quick glance at the document tabs will show you how far a request made it through the system. After reviewing each log (to clear the green markers) we submit another request. In the following screenshot, note that we have a green arrow for process1.log and process2.log, but none for process3.log. So either the second process failed to send the message on, or the third process failed to receive it. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_nWyC8gWd544/StOOGUQUlSI/AAAAAAAAAVA/iZV8Hu0dANY/s1600-h/Error3.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 310px;" src="http://3.bp.blogspot.com/_nWyC8gWd544/StOOGUQUlSI/AAAAAAAAAVA/iZV8Hu0dANY/s400/Error3.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5391809418060141858" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-2430826240729741387?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/2430826240729741387/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/10/monitoring-log-files-in-real-time.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2430826240729741387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2430826240729741387'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/10/monitoring-log-files-in-real-time.html' title='Monitoring log files in real time'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_nWyC8gWd544/StONx35VfTI/AAAAAAAAAUo/Mc45oWd7EzE/s72-c/NewSession.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-2532608516900304151</id><published>2009-09-21T09:43:00.003-05:00</published><updated>2009-09-21T10:44:08.002-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='refactoring'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Cleaning up enumerations</title><content type='html'>When working on existing code I occasionally run into an enumeration class similar to this:&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20   \cf2 public\cf0  \cf2 class\cf0  \cf10 PowertoolsConstants\par ??\cf0   \{\par ??      \cf2 public\cf0  \cf2 enum\cf0  \cf10 Powertools\par ??\cf0       \{\par ??          PowerDrill = 0, \cf11 // Standard, corded drill\par ??\cf0           Chainsaw,       \cf11 // Everyone's favorite\par ??\cf0           CircularSaw     \cf11 // If the chainsaw is out of gas, use this\par ??\cf0       \}\par ??\par ??      \cf2 public\cf0  \cf2 static\cf0  \cf10 Powertools\cf0  ConvertFromString(\cf2 string\cf0  s)\par ??      \{\par ??          \cf2 switch\cf0  (s)\par ??          \{\par ??              \cf2 case\cf0  \cf13 "PowerDrill"\cf0 :\par ??                  \cf2 return\cf0  \cf10 Powertools\cf0 .PowerDrill;\par ??              \cf2 case\cf0  \cf13 "0"\cf0 :\par ??                  \cf2 return\cf0  \cf10 Powertools\cf0 .PowerDrill;\par ??              \cf2 case\cf0  \cf13 "Chainsaw"\cf0 :\par ??                  \cf2 return\cf0  \cf10 Powertools\cf0 .Chainsaw;\par ??              \cf2 case\cf0  \cf13 "1"\cf0 :\par ??                  \cf2 return\cf0  \cf10 Powertools\cf0 .Chainsaw;\par ??              \cf2 case\cf0  \cf13 "CircularSaw"\cf0 :\par ??                  \cf2 return\cf0  \cf10 Powertools\cf0 .CircularSaw;\par ??              \cf2 case\cf0  \cf13 "2"\cf0 :\par ??                  \cf2 return\cf0  \cf10 Powertools\cf0 .CircularSaw;\par ??              \cf2 default\cf0 :\par ??                  \cf2 throw\cf0  \cf2 new\cf0  \cf10 Exception\cf0 (\cf13 "Unknown Powertool"\cf0 );\par ??          \}\par ??      \}\par ??\par ??      \cf2 public\cf0  \cf2 static\cf0  \cf2 string\cf0  ConvertFromPowertool(\cf10 Powertools\cf0  p)\par ??      \{\par ??          \cf2 switch\cf0  (p)\par ??          \{\par ??              \cf2 case\cf0  \cf10 Powertools\cf0 .Chainsaw:\par ??                  \cf2 return\cf0  \cf13 "Chainsaw"\cf0 ;\par ??              \cf2 case\cf0  \cf10 Powertools\cf0 .CircularSaw:\par ??                  \cf2 return\cf0  \cf13 "CircularSaw"\cf0 ;\par ??              \cf2 case\cf0  \cf10 Powertools\cf0 .PowerDrill:\par ??                  \cf2 return\cf0  \cf13 "PowerDrill"\cf0 ;\par ??              \cf2 default\cf0 :\par ??                  \cf2 return\cf0  \cf13 "Unknown"\cf0 ;\par ??          \}\par ??      \}\par ??  \}\par ??}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: teal;"&gt;PowertoolsConstants&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;enum&lt;/span&gt; &lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; PowerDrill = 0, &lt;span style="color: green;"&gt;// Standard, corded drill&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Chainsaw,&amp;nbsp; &amp;nbsp; &amp;nbsp;  &lt;span style="color: green;"&gt;// Everyone's favorite&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; CircularSaw&amp;nbsp; &amp;nbsp;  &lt;span style="color: green;"&gt;// If the chainsaw is out of gas, use this&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: teal;"&gt;Powertools&lt;/span&gt; ConvertFromString(&lt;span style="color: blue;"&gt;string&lt;/span&gt; s)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;switch&lt;/span&gt; (s)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;case&lt;/span&gt; &lt;span style="color: maroon;"&gt;"PowerDrill"&lt;/span&gt;:&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;.PowerDrill;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;case&lt;/span&gt; &lt;span style="color: maroon;"&gt;"0"&lt;/span&gt;:&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;.PowerDrill;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;case&lt;/span&gt; &lt;span style="color: maroon;"&gt;"Chainsaw"&lt;/span&gt;:&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;.Chainsaw;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;case&lt;/span&gt; &lt;span style="color: maroon;"&gt;"1"&lt;/span&gt;:&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;.Chainsaw;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;case&lt;/span&gt; &lt;span style="color: maroon;"&gt;"CircularSaw"&lt;/span&gt;:&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;.CircularSaw;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;case&lt;/span&gt; &lt;span style="color: maroon;"&gt;"2"&lt;/span&gt;:&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;.CircularSaw;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;default&lt;/span&gt;:&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: teal;"&gt;Exception&lt;/span&gt;(&lt;span style="color: maroon;"&gt;"Unknown Powertool"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; ConvertFromPowertool(&lt;span style="color: teal;"&gt;Powertools&lt;/span&gt; p)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;switch&lt;/span&gt; (p)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;case&lt;/span&gt; &lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;.Chainsaw:&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: maroon;"&gt;"Chainsaw"&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;case&lt;/span&gt; &lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;.CircularSaw:&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: maroon;"&gt;"CircularSaw"&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;case&lt;/span&gt; &lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;.PowerDrill:&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: maroon;"&gt;"PowerDrill"&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;default&lt;/span&gt;:&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; &lt;span style="color: maroon;"&gt;"Unknown"&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Nothing too complex, but it can be cleaned up a bit. For starters, accessing the enum currently requires referencing the class:&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20   \cf10 PowertoolsConstants\cf0 .\cf10 Powertools\cf0  tool =\par ??      \cf10 PowertoolsConstants\cf0 .\cf10 Powertools\cf0 .Chainsaw;\par ??}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: teal;"&gt;PowertoolsConstants&lt;/span&gt;.&lt;span style="color: teal;"&gt;Powertools&lt;/span&gt; tool =&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: teal;"&gt;PowertoolsConstants&lt;/span&gt;.&lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;.Chainsaw;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;If we move the enum declaration above the class we can remove the class reference:&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20   \cf10 Powertools\cf0  tool = \cf10 Powertools\cf0 .Chainsaw;}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: teal;"&gt;Powertools&lt;/span&gt; tool = &lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;.Chainsaw;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Next is addressing the two methods in the class: ConvertFromString and ConvertFromPowertool.  The purpose of these methods is to switch between our enumeration and a string representation of the enum, perhaps to store values in an xml file or database.  As the .Net Framework already contains this functionality, the methods are not necessary and can be deleted.&lt;br /&gt;&lt;br /&gt;To convert from an enum value to a string we can use Enum.GetName&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20   \cf2 string\cf0  toolName = \cf10 Enum\cf0 .GetName(\cf2 typeof\cf0 (\cf10 Powertools\cf0 ), tool);}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt; toolName = &lt;span style="color: teal;"&gt;Enum&lt;/span&gt;.GetName(&lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;), tool);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;To convert from a string to an enum value we can use Enum.Parse.  Note that this will throw an ArgumentException if an invalid string is passed in.&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20   tool = (\cf10 Powertools\cf0 )\cf10 Enum\cf0 .Parse(\cf2 typeof\cf0 (\cf10 Powertools\cf0 ), toolName);}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; tool = (&lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;)&lt;span style="color: teal;"&gt;Enum&lt;/span&gt;.Parse(&lt;span style="color: blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;), toolName);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;With the two methods removed, the class PowertoolsConstants is empty and can be deleted.&lt;br /&gt;&lt;br /&gt;One final thing to look at are the comments beside the enum values.  These appear to be usage notes.  If a developer using the enum needs to know this information, he shouldn't have to open this code to get it.  The way to correct this is to replace the existing comments with xml-style comments.&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20   \cf2 public\cf0  \cf2 enum\cf0  \cf10 Powertools\par ??\cf0   \{\par ??      \cf15 ///\cf11  \cf15 &amp;lt;summary&amp;gt;\par ??\cf0       \cf15 ///\cf11  Standard, corded drill\par ??\cf0       \cf15 ///\cf11  \cf15 &amp;lt;/summary&amp;gt;\par ??\cf0       PowerDrill = 0,\par ??\par ??      \cf15 ///\cf11  \cf15 &amp;lt;summary&amp;gt;\par ??\cf0       \cf15 ///\cf11  Everyone's favorite\par ??\cf0       \cf15 ///\cf11  \cf15 &amp;lt;/summary&amp;gt;\par ??\cf0       Chainsaw,\par ??\par ??      \cf15 ///\cf11  \cf15 &amp;lt;summary&amp;gt;\par ??\cf0       \cf15 ///\cf11  If the chainsaw is out of gas, use this\par ??\cf0       \cf15 ///\cf11  \cf15 &amp;lt;/summary&amp;gt;\par ??\cf0       CircularSaw\par ??  \}\par ??}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;enum&lt;/span&gt; &lt;span style="color: teal;"&gt;Powertools&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;span style="color: gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; Standard, corded drill&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;span style="color: gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; PowerDrill = 0,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;span style="color: gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; Everyone's favorite&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;span style="color: gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; Chainsaw,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;span style="color: gray;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; If the chainsaw is out of gas, use this&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: gray;"&gt;///&lt;/span&gt;&lt;span style="color: green;"&gt; &lt;/span&gt;&lt;span style="color: gray;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; CircularSaw&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Doing this will provide the developer with Intellisense hints as they code:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nWyC8gWd544/SrecmNq371I/AAAAAAAAAUg/Polk_S9Adwc/s1600-h/intellisense.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 103px;" src="http://1.bp.blogspot.com/_nWyC8gWd544/SrecmNq371I/AAAAAAAAAUg/Polk_S9Adwc/s400/intellisense.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5383944059863166802" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-2532608516900304151?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/2532608516900304151/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/09/cleaning-up-enumerations.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2532608516900304151'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2532608516900304151'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/09/cleaning-up-enumerations.html' title='Cleaning up enumerations'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nWyC8gWd544/SrecmNq371I/AAAAAAAAAUg/Polk_S9Adwc/s72-c/intellisense.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-7418502614140458316</id><published>2009-08-19T21:55:00.005-05:00</published><updated>2009-08-19T22:18:13.707-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='NUnit'/><title type='text'>Parameterized tests in NUnit</title><content type='html'>In an &lt;a href="http://automaticchainsaw.blogspot.com/2009/01/row-tests-in-nunit.html" title="Row tests in NUnit"&gt;earlier post&lt;/a&gt; I showed how to pass parameters to test methods using an NUnit RowTest extension.  As of version 2.5, the extensions are no longer packaged with the NUnit installer. The good news is that the addition of parameterized tests replaces the RowTest and adds a number of new features as well.&lt;br /&gt;&lt;br /&gt;For reference, my previous RowTest looked like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;[&lt;span style="color: teal;"&gt;RowTest&lt;/span&gt;]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;[&lt;span style="color: teal;"&gt;Row&lt;/span&gt;(2, 3)]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;[&lt;span style="color: teal;"&gt;Row&lt;/span&gt;(-1, -4)]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; AddTwoNumbers(&lt;span style="color: blue;"&gt;int&lt;/span&gt; x, &lt;span style="color: blue;"&gt;int&lt;/span&gt; y)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: teal;"&gt;Assert&lt;/span&gt;.AreEqual(x + y, Add(x, y),&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: maroon;"&gt;"Add returned incorrect result"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;A basic switch to a parameterized test is a matter of dropping the RowTest attribute and replacing each Row attribute with a similarly-formatted TestCase attribute.  The new code, which creates two distinct tests as before, looks like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;[&lt;span style="color: teal;"&gt;TestCase&lt;/span&gt;(2, 3)]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;[&lt;span style="color: teal;"&gt;TestCase&lt;/span&gt;(-1, -4)]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; AddTwoNumbers(&lt;span style="color: blue;"&gt;int&lt;/span&gt; x, &lt;span style="color: blue;"&gt;int&lt;/span&gt; y)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: teal;"&gt;Assert&lt;/span&gt;.AreEqual(x + y, Add(x, y),&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: maroon;"&gt;"Add returned incorrect result"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;In addition to single parameters you can now specify ranges. If I want to test values of X from 1 to 5, with a Y value of 1, I can do so using the Range and Values attributes, like so:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;[&lt;span style="color: teal;"&gt;Test&lt;/span&gt;]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; AddTwoNumbers(&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; [&lt;span style="color: teal;"&gt;Range&lt;/span&gt;(1, 5)]&lt;span style="color: blue;"&gt;int&lt;/span&gt; x,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; [&lt;span style="color: teal;"&gt;Values&lt;/span&gt;(1)]&lt;span style="color: blue;"&gt;int&lt;/span&gt; y)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: teal;"&gt;Assert&lt;/span&gt;.AreEqual(x + y, Add(x, y),&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: maroon;"&gt;"Add returned incorrect result"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;In the test runner, this shows up as five distinct unit tests&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nWyC8gWd544/Soy7d9UnInI/AAAAAAAAAUI/hrG6n_sm2Lk/s1600-h/rangetest.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 179px; height: 104px;" src="http://1.bp.blogspot.com/_nWyC8gWd544/Soy7d9UnInI/AAAAAAAAAUI/hrG6n_sm2Lk/s400/rangetest.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5371874578897773170" /&gt;&lt;/a&gt;&lt;br /&gt;If I specify the range 1-5 for both X and Y, NUnit defaults to creating 25 unique tests.  This is the default Combinatorial attribute.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_nWyC8gWd544/Soy7ptHuIJI/AAAAAAAAAUQ/a1UyBlBzckc/s1600-h/comb.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 195px; height: 149px;" src="http://3.bp.blogspot.com/_nWyC8gWd544/Soy7ptHuIJI/AAAAAAAAAUQ/a1UyBlBzckc/s400/comb.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5371874780707168402" /&gt;&lt;/a&gt;&lt;br /&gt;If I wish to use a value from each range only once, I instead mark the test as Sequential&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;[&lt;span style="color: teal;"&gt;Test&lt;/span&gt;, &lt;span style="color: teal;"&gt;Sequential&lt;/span&gt;]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; AddTwoNumbers(&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; [&lt;span style="color: teal;"&gt;Range&lt;/span&gt;(1, 5)]&lt;span style="color: blue;"&gt;int&lt;/span&gt; x,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; [&lt;span style="color: teal;"&gt;Range&lt;/span&gt;(1, 5)]&lt;span style="color: blue;"&gt;int&lt;/span&gt; y)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: teal;"&gt;Assert&lt;/span&gt;.AreEqual(x + y, Add(x, y),&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: maroon;"&gt;"Add returned incorrect result"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;which produces the desired effect&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_nWyC8gWd544/Soy70jIepZI/AAAAAAAAAUY/DiQfx6OkJsQ/s1600-h/sequence.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 198px; height: 119px;" src="http://3.bp.blogspot.com/_nWyC8gWd544/Soy70jIepZI/AAAAAAAAAUY/DiQfx6OkJsQ/s400/sequence.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5371874967004554642" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-7418502614140458316?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/7418502614140458316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/08/parameterized-tests-in-nunit.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7418502614140458316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7418502614140458316'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/08/parameterized-tests-in-nunit.html' title='Parameterized tests in NUnit'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nWyC8gWd544/Soy7d9UnInI/AAAAAAAAAUI/hrG6n_sm2Lk/s72-c/rangetest.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-3394433014220415991</id><published>2009-08-12T11:29:00.007-05:00</published><updated>2009-08-12T11:53:07.555-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Save WinForm control values between executions</title><content type='html'>Say I have a test application that submits info to a webservice.  Because this webservice has a few issues, I may need to retry a request several times to get a valid response.  I've added a control to set the number of retries.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nWyC8gWd544/SoLustoGfPI/AAAAAAAAATY/6xDlh9Gb5tQ/s1600-h/1_FormSetting.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 185px; height: 95px;" src="http://1.bp.blogspot.com/_nWyC8gWd544/SoLustoGfPI/AAAAAAAAATY/6xDlh9Gb5tQ/s400/1_FormSetting.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5369116157708500210" /&gt;&lt;/a&gt;&lt;br /&gt;Specifying the control's &lt;i&gt;Value&lt;/i&gt; property at design-time sets the starting value at runtime. If a user wants to set a different value, he must do so each time he starts the app. To make things more user-friendly it would be better to save the control's value between executions.&lt;br /&gt;&lt;br /&gt;To do so, start by selecting the desired control in the designer. In the Properties window, expand the ApplicationSettings entry and select the ellipsis (...) for the PropertyBinding sub-entry.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nWyC8gWd544/SoLu0VSbkbI/AAAAAAAAATg/BSejk7I9A30/s1600-h/2_PropertyBinding.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 330px; height: 217px;" src="http://1.bp.blogspot.com/_nWyC8gWd544/SoLu0VSbkbI/AAAAAAAAATg/BSejk7I9A30/s400/2_PropertyBinding.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5369116288614109618" /&gt;&lt;/a&gt;&lt;br /&gt;In the Application Settings dialog that appears, select the dropdown next to the 'Value' entry, as this is the property we wish to persist.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nWyC8gWd544/SoLu9XKwcxI/AAAAAAAAATo/PfvCMhXgMBk/s1600-h/3_ApplicationSettings.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 385px; height: 305px;" src="http://2.bp.blogspot.com/_nWyC8gWd544/SoLu9XKwcxI/AAAAAAAAATo/PfvCMhXgMBk/s400/3_ApplicationSettings.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5369116443737617170" /&gt;&lt;/a&gt;&lt;br /&gt;Select the '(New...)' link from the popup, which brings up the New Application Setting dialog. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nWyC8gWd544/SoLvFgwy7iI/AAAAAAAAATw/Tm1XEzqi-OU/s1600-h/4_NewApplicationSetting.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 334px; height: 220px;" src="http://1.bp.blogspot.com/_nWyC8gWd544/SoLvFgwy7iI/AAAAAAAAATw/Tm1XEzqi-OU/s400/4_NewApplicationSetting.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5369116583752035874" /&gt;&lt;/a&gt;&lt;br /&gt;Specify the default value and name of the config setting (and modify the Scope if necessary) and press OK.  This will update the Application Settings dialog to show the newly added entry.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nWyC8gWd544/SoLvOCH0ePI/AAAAAAAAAT4/HzKk_VuqvEw/s1600-h/5_ApplicationSettings2.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 381px; height: 263px;" src="http://1.bp.blogspot.com/_nWyC8gWd544/SoLvOCH0ePI/AAAAAAAAAT4/HzKk_VuqvEw/s400/5_ApplicationSettings2.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5369116730145929458" /&gt;&lt;/a&gt;&lt;br /&gt;Press OK to close the dialog. With the property binding set, the application will automatically load the value at startup. The only thing left is to save the modified value. In the form's FormClosing event handler, add the following line:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;Properties.&lt;span style="color: teal;"&gt;Settings&lt;/span&gt;.Default.Save();&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;At this point the change is ready to test.  Start the application and modify the control's value. Without doing anything else, close the application.  Now restart the app.  Note the control contains the modified value.&lt;br /&gt;&lt;br /&gt;It would seem the desired functionality is complete but there is one more item that needs to address. If you look for the saved settings file, you will find it under &lt;br /&gt;&lt;br /&gt;&lt;i&gt;C:\Documents and Settings\&amp;lt;username&amp;gt;\Local Settings\Application Data\&amp;lt;Company&amp;gt;\&amp;lt;AppName&amp;gt;\&amp;lt;version&amp;gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;If the version number for the application is changed, the previously saved setting won't be loaded. The application needs to know to upgrade the saved settings the first time it runs.&lt;br /&gt;&lt;br /&gt;Start by adding a new application setting called UpgradeSettings. This will be used to make sure we only upgrade the settings once. Otherwise, any newly saved settings will be replaced by the previous version's settings every time the app starts.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_nWyC8gWd544/SoLvX76fCVI/AAAAAAAAAUA/IFBKeR4jOBU/s1600-h/6_UpgradeSettingsProperty.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 141px;" src="http://3.bp.blogspot.com/_nWyC8gWd544/SoLvX76fCVI/AAAAAAAAAUA/IFBKeR4jOBU/s400/6_UpgradeSettingsProperty.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5369116900278077778" /&gt;&lt;/a&gt;&lt;br /&gt;The final step is to add the upgrade logic to Program.cs.  In the Main method, add the following code immediately before the call to Application.Run.&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;if&lt;/span&gt; (&lt;span style="color: teal;"&gt;Convert&lt;/span&gt;.ToBoolean(Properties.&lt;span style="color: teal;"&gt;Settings&lt;/span&gt;.Default[&lt;span style="color: maroon;"&gt;"UpgradeSettings"&lt;/span&gt;]))&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; Properties.&lt;span style="color: teal;"&gt;Settings&lt;/span&gt;.Default.Upgrade();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; Properties.&lt;span style="color: teal;"&gt;Settings&lt;/span&gt;.Default[&lt;span style="color: maroon;"&gt;"UpgradeSettings"&lt;/span&gt;] = &lt;span style="color: blue;"&gt;false&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-3394433014220415991?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/3394433014220415991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/08/save-winform-control-values-between.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/3394433014220415991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/3394433014220415991'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/08/save-winform-control-values-between.html' title='Save WinForm control values between executions'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nWyC8gWd544/SoLustoGfPI/AAAAAAAAATY/6xDlh9Gb5tQ/s72-c/1_FormSetting.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-1895777069002416442</id><published>2009-07-14T19:28:00.002-05:00</published><updated>2009-07-14T19:36:37.425-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>No-hassle SQL connection strings</title><content type='html'>Most applications working with a database handle the connection string in one of two ways: Hard-coding the full string or doing some amount of string concatenation. A typical concatenation method looks something like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; OldMethod(&lt;span style="color: blue;"&gt;string&lt;/span&gt; server, &lt;span style="color: blue;"&gt;string&lt;/span&gt; database,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt; username, &lt;span style="color: blue;"&gt;string&lt;/span&gt; password)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt; connectionString = &lt;span style="color: maroon;"&gt;"Data Source="&lt;/span&gt; + server + &lt;span style="color: maroon;"&gt;";"&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; connectionString += &lt;span style="color: maroon;"&gt;"Initial Catalog="&lt;/span&gt; + database + &lt;span style="color: maroon;"&gt;";"&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; connectionString += &lt;span style="color: maroon;"&gt;"User ID="&lt;/span&gt; + username + &lt;span style="color: maroon;"&gt;";"&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; connectionString += &lt;span style="color: maroon;"&gt;"Password="&lt;/span&gt; + password;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; connectionString;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;I admit this is fairly simple code. The only potential issues might be a property name typo or a misplaced (or missing) semicolon. But why hassle with even that much when the dotNet Framework has the same functionality built into the SqlConnectionStringBuilder class?  With a reference to System.Data.SqlClient, the above method can be replaced with:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;string&lt;/span&gt; NewMethod(&lt;span style="color: blue;"&gt;string&lt;/span&gt; server, &lt;span style="color: blue;"&gt;string&lt;/span&gt; database,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt; username, &lt;span style="color: blue;"&gt;string&lt;/span&gt; password)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: teal;"&gt;SqlConnectionStringBuilder&lt;/span&gt; connBuilder &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: teal;"&gt;SqlConnectionStringBuilder&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; connBuilder.UserID = username;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; connBuilder.Password = password;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; connBuilder.InitialCatalog = database;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; connBuilder.DataSource = server;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; connBuilder.ToString();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;In either case, the output is identical:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Data Source=myServer;Initial Catalog=myDatabase;User ID=myUser;Password=myPassword&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Note: If you are working with a database other than MSSQL, there are several other classes derived from the common DbConnectionStringBuilder base class, such as OdbcConnectionStringBuilder and OracleConnectionStringBuilder.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-1895777069002416442?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/1895777069002416442/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/07/no-hassle-sql-connection-strings.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1895777069002416442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1895777069002416442'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/07/no-hassle-sql-connection-strings.html' title='No-hassle SQL connection strings'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-1660953355136317450</id><published>2009-07-06T02:15:00.000-05:00</published><updated>2009-09-21T10:47:03.107-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='refactoring'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Quickly escape strings in xml</title><content type='html'>If you spend much time working with xml, you will find yourself needing to escape strings.  Replacing '&lt;' with '&amp;amp;lt;' for example.  Usually the code written to do so looks something like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 8pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;escapedItem = itemToEscape.Replace(&lt;span style="color: maroon;"&gt;"&amp;amp;"&lt;/span&gt;, &lt;span style="color: maroon;"&gt;"&amp;amp;amp;"&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; .Replace(&lt;span style="color: maroon;"&gt;"&amp;lt;"&lt;/span&gt;, &lt;span style="color: maroon;"&gt;"&amp;amp;lt;"&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; .Replace(&lt;span style="color: maroon;"&gt;"&amp;gt;"&lt;/span&gt;, &lt;span style="color: maroon;"&gt;"&amp;amp;gt;"&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; .Replace(&lt;span style="color: maroon;"&gt;"'"&lt;/span&gt;, &lt;span style="color: maroon;"&gt;"&amp;amp;apos;"&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; .Replace(&lt;span style="color: maroon;"&gt;"\""&lt;/span&gt;, &lt;span style="color: maroon;"&gt;"&amp;amp;quot;"&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Though this technically works, there is an easier way built right in to the .Net framework.  If we reference System.Security we can replace the above code with&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 8pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;escapedItem = &lt;span style="color: teal;"&gt;SecurityElement&lt;/span&gt;.Escape(itemToEscape);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;In both cases, the string&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 8pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: maroon;"&gt;If (x &amp;lt; 2) &amp;amp; (y &amp;gt; 3), where \"x\" isn't...&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;is replaced with&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 8pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: maroon;"&gt;If (x &amp;amp;lt; 2) &amp;amp;amp; (y &amp;amp;gt; 3), where &amp;amp;quot;x&amp;amp;quot; isn&amp;amp;apos;t...&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-1660953355136317450?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/1660953355136317450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/07/quickly-escape-strings-in-xml.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1660953355136317450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1660953355136317450'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/07/quickly-escape-strings-in-xml.html' title='Quickly escape strings in xml'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-7401603997570724843</id><published>2009-05-19T13:29:00.001-05:00</published><updated>2009-05-19T13:29:52.990-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.Net'/><title type='text'>An easier way to manage CruiseControl.Net projects</title><content type='html'>In a &lt;a href="http://automaticchainsaw.blogspot.com/2007/05/reducing-size-of-ccnetconfig.html" title="Reducing the size of ccnet.config"&gt;much older post&lt;/a&gt; I showed a quick way to remove duplication in a CruiseControl.Net (CCNet) config file.  Since then, CCNet has added a &lt;a href="http://confluence.public.thoughtworks.org/display/CCNET/Configuration+Preprocessor" title="Configuration Preprocessor (documentation)"&gt;Configuration Preprocessor&lt;/a&gt; to not only simplify this process, but also split the ccnet.config into multiple files - one per project.&lt;br /&gt;&lt;br /&gt;To start with, we need to modify ccnet.config to specify the correct xml namespace:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 8pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;cruisecontrol&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;xmlns:cb&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;urn:ccnet.config.builder&lt;/span&gt;"&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Now we move an existing project from ccnet.config into a separate file.  Note this new file starts with 'project' as the root node, and must also have the correct xml namespace.&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 8pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;project&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;xmlns:cb&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;urn:ccnet.config.builder&lt;/span&gt;"&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;My Test Project&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;triggers&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;intervalTrigger&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;seconds&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;60&lt;/span&gt;"&lt;span style="color: blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;triggers&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;sourcecontrol&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;svn&lt;/span&gt;"&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;executable&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;svn.exe&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;executable&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;trunkUrl&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;svn://MySourceServer/myAppPath&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;trunkUrl&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;workingDirectory&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;C:\CCNetProjects\MyTestProject&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;workingDirectory&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;username&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;svnUser&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;username&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;password&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;svnPassword&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;password&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;autoGetSource&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;true&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;autoGetSource&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;sourcecontrol&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;tasks&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;msbuild&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;logger&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;c:\ThoughtWorks.CruiseControl.MSBuild.dll&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;logger&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;projectFile&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;MyTestProject.sln&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;projectFile&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;buildArgs&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;/noconsolelogger&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;buildArgs&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;targets&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;Build&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;targets&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;workingDirectory&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;D:\CCNetProjects\MyTestProject&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;workingDirectory&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;msbuild&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;tasks&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;publishers&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;statistics&lt;/span&gt;&lt;span style="color: blue;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;xmllogger&lt;/span&gt;&lt;span style="color: blue;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;artifactcleanup&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;cleanUpMethod&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;KeepLastXBuilds&lt;/span&gt;"&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;cleanUpValue&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;25&lt;/span&gt;"&lt;span style="color: blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;publishers&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;project&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;In the main ccnet.config, our project information can be replaced with an include that points to our new project config:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 8pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;cb:include&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;href&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;C:\MyTestApp.ccnet.config&lt;/span&gt;"&lt;span style="color: blue;"&gt; /&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Instead of one massive config file, we now split it by project.  This makes adding, removing, or modifying projects much easier.  As an added bonus, CCNet monitors the project-specific config files and reloads them if anything changes.&lt;br /&gt;&lt;br /&gt;I mentioned that we can also use the preprocessor to reduce duplication.  In the project config above, note the Subversion username and password nodes:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 8pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;username&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;svnUser&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;username&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;password&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;svnPassword&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;password&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;If we define these values in each individual config, changing them requires a find/replace across multiple files.  What we want to do is define them once in the main ccnet.config and then include them in our project configs.  To do this, we start by adding the following to ccnet.config&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 8pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;cb:define&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;name&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;svnCredentials&lt;/span&gt;"&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;username&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;svnUser&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;username&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;password&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;svnPasswrod&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;password&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;cb:define&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;In our project config we can replace the two credential nodes with a single reference to 'svnCredentials'.  If we ever change the account our buildserver uses to pull code, we only need to change the credentials once.&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 8pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;sourcecontrol&lt;/span&gt;&lt;span style="color: blue;"&gt; &lt;/span&gt;&lt;span style="color: red;"&gt;type&lt;/span&gt;&lt;span style="color: blue;"&gt;=&lt;/span&gt;"&lt;span style="color: blue;"&gt;svn&lt;/span&gt;"&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;executable&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;svn.exe&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;executable&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;trunkUrl&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;svn://MySourceServer/myAppPath&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;trunkUrl&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;workingDirectory&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;C:\CCNetProjects\MyTestProject&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;workingDirectory&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;cb:svnCredentials&lt;/span&gt;&lt;span style="color: blue;"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;nbsp; &amp;nbsp; &amp;lt;&lt;/span&gt;&lt;span style="color: #a31515;"&gt;autoGetSource&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;true&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;autoGetSource&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515;"&gt;sourcecontrol&lt;/span&gt;&lt;span style="color: blue;"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-7401603997570724843?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/7401603997570724843/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/05/easier-way-to-manage-cruisecontrolnet.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7401603997570724843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7401603997570724843'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/05/easier-way-to-manage-cruisecontrolnet.html' title='An easier way to manage CruiseControl.Net projects'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-7402094360735649649</id><published>2009-04-06T10:20:00.007-05:00</published><updated>2009-04-06T13:09:43.230-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>Mmc load failure</title><content type='html'>After running our &lt;a href="http://automaticchainsaw.blogspot.com/2009/03/runtime-profiling-com-registration.html" title="Runtime profiling a COM registration failure"&gt;legacy installer&lt;/a&gt; we ran into yet another problem - the Computer Management administrative app quit working.  Attempting to start it gave an error stating:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;MMC cannot open the file C:\WINDOWS\system32\compmgmt.msc.&lt;br /&gt;&lt;br /&gt;This may be because the file does not exist, is not an MMC console, or was created by a later version of MMC. This may also be because you do not have sufficient access rights to the file.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;To debug this particular issue, we turn to &lt;a href="http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx" title="Process Monitor"&gt;Process Monitor&lt;/a&gt;.  When we start up the app, the first item shown is a filter dialog.  For this session, we need to add mmc.exe to the list of processes to monitor.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nWyC8gWd544/Sdod5S1QnYI/AAAAAAAAASg/5sG_rm32goI/s1600-h/ProcMon+filter.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 250px;" src="http://2.bp.blogspot.com/_nWyC8gWd544/Sdod5S1QnYI/AAAAAAAAASg/5sG_rm32goI/s400/ProcMon+filter.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5321598779836636546" /&gt;&lt;/a&gt;&lt;br /&gt;Though it's useful to see all activity for a given process, we are generally focused on errors.  To make this easier, we want to highlight any log entries that do not have a Result of 'SUCCESS'&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nWyC8gWd544/SdoeBfvcqHI/AAAAAAAAASo/3keN9pFdNBs/s1600-h/ProcMon+highlight+errors.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 239px;" src="http://2.bp.blogspot.com/_nWyC8gWd544/SdoeBfvcqHI/AAAAAAAAASo/3keN9pFdNBs/s400/ProcMon+highlight+errors.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5321598920740874354" /&gt;&lt;/a&gt;&lt;br /&gt;Once we have Process Monitor configured and running, we can start the Computer Management tool.  The logs will quickly fill up with registry and filesystem events, many of which will be highlighted&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nWyC8gWd544/SdoeIqb-lxI/AAAAAAAAASw/oglLgxm9HuQ/s1600-h/ProcMon+output.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 228px;" src="http://1.bp.blogspot.com/_nWyC8gWd544/SdoeIqb-lxI/AAAAAAAAASw/oglLgxm9HuQ/s400/ProcMon+output.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5321599043871086354" /&gt;&lt;/a&gt;&lt;br /&gt;In the above screenshot, notice the registry ReadOpenKey failures for various items under "HKCR\CLSID\{2933BF90-7B36-11d2-B20E-00C04F983E60}".  I don't know off hand what those sub-items specify, but without them I do know you will be unable to load the associated COM object.  To determine what dll was at fault, we went to another computer and looked for that section in the registry.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nWyC8gWd544/SdoeOMzx0_I/AAAAAAAAAS4/DYs5JjeezKc/s1600-h/RegEdit+with+CLSID+on+good+machine.PNG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 160px;" src="http://2.bp.blogspot.com/_nWyC8gWd544/SdoeOMzx0_I/AAAAAAAAAS4/DYs5JjeezKc/s400/RegEdit+with+CLSID+on+good+machine.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5321599138997064690" /&gt;&lt;/a&gt;&lt;br /&gt;Note above the default value of "C:\WINDOWS\system32\msxml3.dll."  For whatever reason, our installer was unregistering this system dll - definitely not a good thing.  Fixing the problem on the broken box was as simple as running regsvr32 on msxml3.dll.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-7402094360735649649?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/7402094360735649649/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/04/mmc-load-failure.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7402094360735649649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7402094360735649649'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/04/mmc-load-failure.html' title='Mmc load failure'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_nWyC8gWd544/Sdod5S1QnYI/AAAAAAAAASg/5sG_rm32goI/s72-c/ProcMon+filter.PNG' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-5958038634894123144</id><published>2009-03-27T10:58:00.009-05:00</published><updated>2009-03-27T12:15:37.188-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>Runtime profiling a COM registration failure</title><content type='html'>As a continuation of my &lt;a href="http://automaticchainsaw.blogspot.com/2009/03/com-dll-registration-failure.html" title="COM dll registration failure"&gt;last post&lt;/a&gt;, we had another registration error with the same legacy installer.  This time the problem was with mssoap30.dll.  Loading the dll in Dependency Walker revealed a single error with dwmapi.dll.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_nWyC8gWd544/Sc0HPGVSciI/AAAAAAAAASA/6i4w_hxSntQ/s1600-h/initial+depends.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_nWyC8gWd544/Sc0HPGVSciI/AAAAAAAAASA/6i4w_hxSntQ/s400/initial+depends.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5317914690973757986" /&gt;&lt;/a&gt;&lt;br /&gt;With a bit of web searching we found that dwmapi.dll is &lt;a href="http://stackoverflow.com/questions/173433/how-to-fix-dwmapidll-delay-load-dependency-under-winxp" title="How to fix DWMAPI.DLL delay-load dependency under WinXP?"&gt;only present&lt;/a&gt; on Vista and later machines. Since we weren't using that dll directly it shouldn't be the cause of our issue on Windows XP.&lt;br /&gt;&lt;br /&gt;At this point it would appear we have all necessary dlls and that our problem must be elsewhere.  The documentation on Dependency Walker, however, provides some useful information:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;When a module is first opened by Dependency Walker, it is immediately scanned for all implicit, delay-load, and forwarded dependencies. Once all the modules have been scanned, the results are displayed. In addition to these known dependencies, &lt;b&gt;modules are free to load other modules at run-time without any prior warning to the operating system.&lt;/b&gt; These types of dependencies are known as dynamic or explicit dependencies. There is really &lt;b&gt;no way to detect dynamic dependencies without actually running the application and watching it to see what modules it loads at run-time.&lt;/b&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Version 2.0 and later of Dependency Walker provides a Profile option from the menu.  If you have a dll loaded, however, the item is disabled - you have to load an executable first.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_nWyC8gWd544/Sc0HVocSBjI/AAAAAAAAASI/Ugx1xQvQ9lo/s1600-h/disabled+menu+items.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 169px;" src="http://4.bp.blogspot.com/_nWyC8gWd544/Sc0HVocSBjI/AAAAAAAAASI/Ugx1xQvQ9lo/s400/disabled+menu+items.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5317914803209111090" /&gt;&lt;/a&gt;&lt;br /&gt;For this to work, you need to load regsvr32.exe, which will enable the menu items.  Once done, select Profile &gt; Start Profiling to bring up the Profile Module dialog.  The only necessary change is to add the dll being registered to the "Program arguments" setting.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_nWyC8gWd544/Sc0HcZeeqUI/AAAAAAAAASQ/Zv0th_MeA1M/s1600-h/profile+module+settings.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 267px;" src="http://3.bp.blogspot.com/_nWyC8gWd544/Sc0HcZeeqUI/AAAAAAAAASQ/Zv0th_MeA1M/s400/profile+module+settings.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5317914919450880322" /&gt;&lt;/a&gt;&lt;br /&gt;Press OK and wait for the application to run.  Eventually you will see the usual registration error message box, which you can simply click to continue.  Once finished, scrolling through the results shows a couple errors for mssoapr3.dll.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_nWyC8gWd544/Sc0HsCf4e9I/AAAAAAAAASY/vQl_WC5Rv4w/s1600-h/missing+runtime+dependencies.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_nWyC8gWd544/Sc0HsCf4e9I/AAAAAAAAASY/vQl_WC5Rv4w/s400/missing+runtime+dependencies.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5317915188160658386" /&gt;&lt;/a&gt;&lt;br /&gt;The first error states that the file path specified can't be found.  Double-clicking the error shows that it is looking for the dll under "c:\temp\1033".  The second states that it cannot find the file - this time in the same folder as the dll we tried to register.  So it seems either location is valid for this particular dependency.&lt;br /&gt;&lt;br /&gt;Once we add mssoapr3.dll to the same folder, mssoap30.dll registers without issue.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-5958038634894123144?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/5958038634894123144/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/03/runtime-profiling-com-registration.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/5958038634894123144'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/5958038634894123144'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/03/runtime-profiling-com-registration.html' title='Runtime profiling a COM registration failure'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_nWyC8gWd544/Sc0HPGVSciI/AAAAAAAAASA/6i4w_hxSntQ/s72-c/initial+depends.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-977882512570103216</id><published>2009-03-24T13:04:00.005-05:00</published><updated>2009-03-24T16:10:52.261-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>COM dll registration failure</title><content type='html'>Every shop has at least one legacy piece of software they have to support.  Written in VB6.  With lots of copy/paste code and sections that may or may not still be active.  By a developer long since gone from the company.  It's bad enough to have to deal with the code itself, but try and rebuild the equally-convoluted installer and you might just go mad.&lt;br /&gt;&lt;br /&gt;Our problem wasn't in rebuilding the installer, per-se, but in getting it to run successfully afterward.  One issue we ran into were COM dlls that failed to self register.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_nWyC8gWd544/Sckhc6M5wWI/AAAAAAAAARw/UpclipvCOJM/s1600-h/registration+error+on+install.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 298px;" src="http://4.bp.blogspot.com/_nWyC8gWd544/Sckhc6M5wWI/AAAAAAAAARw/UpclipvCOJM/s400/registration+error+on+install.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5316817615631008098" /&gt;&lt;/a&gt;&lt;br /&gt;When we attempted to run &lt;a href="http://support.microsoft.com/kb/249873" title="Explanation of Regsvr32 usage and error messages"&gt;regsvr32&lt;/a&gt; on this particular dll, we were given an error dialog stating:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;LoadLibrary("C:\WINDOWS\system32\pcmcom.dll") failed - The specified module could not be found.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;This particular issue is often due to a missing dependency.  To verify this we opened up &lt;a href="http://www.dependencywalker.com/"&gt;Dependency Walker&lt;/a&gt; and loaded pcmcom.dll.  In the screenshot below, you can see the yellow question mark symbol next to pcm.dll - our missing dependency.  Once we found pcm.dll and its dependencies, pcmcom.dll registered without issue.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_nWyC8gWd544/Sckhq7YAIRI/AAAAAAAAAR4/lY4PkC-S0ag/s1600-h/depends+pcmcom.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 306px;" src="http://3.bp.blogspot.com/_nWyC8gWd544/Sckhq7YAIRI/AAAAAAAAAR4/lY4PkC-S0ag/s400/depends+pcmcom.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5316817856464167186" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-977882512570103216?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/977882512570103216/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/03/com-dll-registration-failure.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/977882512570103216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/977882512570103216'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/03/com-dll-registration-failure.html' title='COM dll registration failure'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_nWyC8gWd544/Sckhc6M5wWI/AAAAAAAAARw/UpclipvCOJM/s72-c/registration+error+on+install.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-7097825531263190644</id><published>2009-03-20T11:27:00.005-05:00</published><updated>2009-03-20T12:06:33.390-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Subversion'/><title type='text'>Subversion revision corruption</title><content type='html'>Say that three times fast...&lt;br /&gt;&lt;br /&gt;We ran into an interesting issue earlier this week with Subversion.  When attempting to perform any sort of operation on one of our repositories, the operation failed with an error stating "Final line in revision file longer than 64 characters  svn: PROPFIND of '/svn/myRepository/myProject'."&lt;br /&gt;&lt;br /&gt;When a checkin is made to Subversion, the file differences are compressed and saved to disk under \myRepository\db\revs\.  Each checkin will be in a separate file named to match the revision number.  Thus revision 1200 is saved to a file named "1200" (no extension.)  If you open one of these files in a text editor, you will mostly see unreadable binary.  One noticeable feature in all of the files is a pair of numbers on the last line - "10550 10745" perhaps.  In our particular case the final revision contained two additional lines following the number pair:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;100.1.1.10 - myUser [16/Mar/2009:10:12:06 -0500] "PROPFIND /svn/myRepository/!svn/bln/2914 HTTP/1.1" 207 464&lt;br /&gt;100.1.1.10 - myUser [16/Mar/2009:10:12:06 -0500] "PROPFIND /svn/myRepository/myProject HTTP/1.1" 207 714&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;These lines are normally found in the Apache log file - not a good sign.  A web search verified that it is a &lt;a href="http://www.szakmeister.net/fsfsverify/" title="Bitten by the “read length line” error?"&gt;known issue with no resolution&lt;/a&gt;.  The good news is that the page links to a Python script that attempts to repair corrupt revisions.  (More information on using the script can be found &lt;a href="http://www.mayurjobanputra.com/index.php/2008/07/20/svnadmin-decompression-of-svndiff-data-failed-and-fsfsverifypy/" title="svnadmin: Decompression of SVNDiff Data failed and fsfsverify.py"&gt;here&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;The bad news?  The script didn't entirely work for us - some of the header info on the compressed diffs had been lost.  Fortunately, it did remove the Apache log info from the tail of the file, so other developers could again work.  The only section now corrupt was the project where the revision error occurred.  This project started returning an error stating "Checksum mismatch while reading representation."&lt;br /&gt;&lt;br /&gt;With the issue isolated, the next step was to remove the corrupt revision.  Unfortunately, the only way to do that in Subversion is to export the good revisions and then build a new repository using those exports.  Say revision 120 is bad and we have a total of 150 revisions.  We start by dumping revisions 1 through 119 to a file:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;svnadmin dump c:\myRepository\ -r1:119 &gt; c:\DumpPart1.dmp&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;We then need an incremental dump for changes 121 through 150:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;svnadmin dump c:\myRepository\ -r121:150 -- incremental &gt; c:\DumpPart2.dmp&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Rename the folder "myRepository" to something else as a quick backup, then create a new database:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;svnadmin create c:\myRepository&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Copy any config files from the backup repository (such as user accounts) then load the dumps into the new database:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;svnadmin load c:\myRepository &lt; c:\DumpPart1.dmp&lt;br /&gt;svnadmin load c:\myRepository &lt; c:\DumpPart2.dmp&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;One item of note:  Loading a Subversion dump effectively creates new checkins for each item in that dump.  All items in the second dump above will have a revision number one lower than previously - checkin 121 in the old database becomes checkin 120 in the new database.  Though I've not seen it, some developers may receive an error if their local code contains a newer revision number than the database.  As I ran a few test checkins after creating the new database, this wasn't a problem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-7097825531263190644?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/7097825531263190644/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/03/subversion-revision-corruption.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7097825531263190644'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7097825531263190644'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/03/subversion-revision-corruption.html' title='Subversion revision corruption'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-7383529926888700836</id><published>2009-03-06T09:18:00.005-06:00</published><updated>2009-03-06T09:47:12.047-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VS2005'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>Debugging InstallUtil.exe</title><content type='html'>The project I'm currently working on contains a Windows service with a number of performance counters.  To run the code on a dev machine, we prefer to do so without first running an msi.  So to get the performance counters installed, we tried to run installutil on the service executable.  Which of course returned a vague error message and rolled back the changes.  Fortunately, this type of problem wasn't too difficult to debug.&lt;br /&gt; &lt;br /&gt;To demonstrate, I've created a new application and added a class that inherits from Installer.  I've overridden the OnBeforeInstall event as follows:&lt;br /&gt; &lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;protected&lt;/span&gt; &lt;span style="color: blue;"&gt;override&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; OnBeforeInstall(&lt;span style="color: #2b91af;"&gt;IDictionary&lt;/span&gt; savedState)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;base&lt;/span&gt;.OnBeforeInstall(savedState);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;string&lt;/span&gt; nullString = &lt;span style="color: blue;"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;int&lt;/span&gt; invalidLength = nullString.Length;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;If I attempt to run "InstallUtil MyApp.exe" I receive the following within the console output:&lt;br /&gt; &lt;br /&gt;&lt;i&gt;An exception occurred in the OnBeforeInstall event handler of MyApp.MyAppInstaller.&lt;br /&gt;System.NullReferenceException: Object reference not set to an instance of an object.&lt;/i&gt;&lt;br /&gt; &lt;br /&gt;For trivial code such as my above sample, tracking down the problem should take most developers all of five minutes.  Once you have a non-trivial amount of code (which was the case at work) you need a little more information.  If I call "InstallUtil /ShowCallStack MyApp.exe" I receive the exact line where the problem occurs:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;An exception occurred during the Install phase.&lt;br /&gt;System.InvalidOperationException: An exception occurred in the OnBeforeInstall e&lt;br /&gt;vent handler of MyApp.MyAppInstaller.&lt;br /&gt;   at System.Configuration.Install.Installer.Install(IDictionary stateSaver)&lt;br /&gt;   at System.Configuration.Install.Installer.Install(IDictionary stateSaver)&lt;br /&gt;   at System.Configuration.Install.AssemblyInstaller.Install(IDictionary savedState)&lt;br /&gt;   at System.Configuration.Install.Installer.Install(IDictionary stateSaver)&lt;br /&gt;   at System.Configuration.Install.TransactedInstaller.Install(IDictionary savedState)&lt;br /&gt;The inner exception System.NullReferenceException was thrown with the following&lt;br /&gt;error message: Object reference not set to an instance of an object..&lt;br /&gt;   at InstalUtilDebugging.MyAppInstaller.OnBeforeInstall(IDictionary savedState)&lt;br /&gt; in &lt;b&gt;C:\source\temp\InstalUtilDebugging\MyAppInstaller.cs:line 23&lt;/b&gt;&lt;br /&gt;   at System.Configuration.Install.Installer.Install(IDictionary stateSaver)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;In many cases, this will be enough to solve the problem.  There may be cases, however, where you need to attach a debugger to the process and step through the code to see where a problem actually started.  To do this I add the following line to the beginning of OnBeforeInstall:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;System.Diagnostics.&lt;span style="color: #2b91af;"&gt;Debugger&lt;/span&gt;.Launch();&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;After I recompile and again run InstallUtil, I am given a JIT Debugger dialog which allow me to attach to the process.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_nWyC8gWd544/SbFD0nQeHxI/AAAAAAAAARg/4HpKfu0OXtM/s1600-h/AttachDebugger.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 370px; height: 400px;" src="http://4.bp.blogspot.com/_nWyC8gWd544/SbFD0nQeHxI/AAAAAAAAARg/4HpKfu0OXtM/s400/AttachDebugger.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5310100006816849682" /&gt;&lt;/a&gt;&lt;br /&gt;I select the instance of VisualStudio that has my install code and click 'Yes' to begin debugging.  You may be given a warning stating "There is no source code available for the current location."  Click 'OK' and press F10 once - this will show the Debugger.Launch statement as the current line of code being executed.  From here debugging works as in any application.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_nWyC8gWd544/SbFEHG-nwFI/AAAAAAAAARo/lZKjdnTuDCc/s1600-h/UnhandledException.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 223px;" src="http://3.bp.blogspot.com/_nWyC8gWd544/SbFEHG-nwFI/AAAAAAAAARo/lZKjdnTuDCc/s400/UnhandledException.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5310100324569563218" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-7383529926888700836?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/7383529926888700836/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/03/debugging-installutilexe.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7383529926888700836'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7383529926888700836'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/03/debugging-installutilexe.html' title='Debugging InstallUtil.exe'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_nWyC8gWd544/SbFD0nQeHxI/AAAAAAAAARg/4HpKfu0OXtM/s72-c/AttachDebugger.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-6951306125923861539</id><published>2009-02-17T16:04:00.007-06:00</published><updated>2009-02-17T16:08:38.943-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VS2005'/><title type='text'>Visual Studio installer projects - which project did I forget to include?</title><content type='html'>I made an interesting discovery while working on a project the other day.  As I watched the compiler output from a particularly large solution I noticed several of the required assemblies were being built &lt;b&gt;after&lt;/b&gt; the installer project.  The reason was that someone forgot to add these assemblies to the installer.  Normally this isn't hard to find and fix, but this particular solution has 150 projects, 149 of which need to be included in the installer.  Manually comparing the list of installer dependencies to the list of projects takes quite a bit of time and is error-prone.  Fortunately we can use the Project Dependencies screen to quickly find the missing items.&lt;br /&gt;&lt;br /&gt;To illustrate, I've create a simple solution with five assembly projects and an installer project.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_nWyC8gWd544/SZs0iMx1CQI/AAAAAAAAAQ4/vRNkmpwtvJY/s1600-h/SolutionListing.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 248px; height: 124px;" src="http://3.bp.blogspot.com/_nWyC8gWd544/SZs0iMx1CQI/AAAAAAAAAQ4/vRNkmpwtvJY/s400/SolutionListing.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5303890748309309698" /&gt;&lt;/a&gt;&lt;br /&gt;As I add each project to the installer, we see the primary output added within the installer&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nWyC8gWd544/SZs0oL9fy3I/AAAAAAAAARA/qYLKBrIuYgo/s1600-h/SolutionListingAfterOneAssembly.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 277px; height: 160px;" src="http://1.bp.blogspot.com/_nWyC8gWd544/SZs0oL9fy3I/AAAAAAAAARA/qYLKBrIuYgo/s400/SolutionListingAfterOneAssembly.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5303890851169028978" /&gt;&lt;/a&gt;&lt;br /&gt;It looks simple enough when you only have a few projects.  Add a couple dozen more and you can see that things are going to become more difficult.&lt;br /&gt;&lt;br /&gt;To get a better view of the installer's dependencies, right-click on the solution in the Solution Explorer and choose "Properties."  On the Property Pages dialog, choose Common Properties &gt; Project Dependencies from the tree on the left.  Under the Project dropdown on the right, select the installer project.&lt;br /&gt;&lt;br /&gt;Here is my installer before adding any projects&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nWyC8gWd544/SZs0vH1iZvI/AAAAAAAAARI/-HUE3Jx9MQw/s1600-h/EmptyInstaller.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 245px;" src="http://4.bp.blogspot.com/_nWyC8gWd544/SZs0vH1iZvI/AAAAAAAAARI/-HUE3Jx9MQw/s400/EmptyInstaller.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5303890970320987890" /&gt;&lt;/a&gt;&lt;br /&gt;After I add AssemblyA to the installer, the Project Dependencies looks like this&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nWyC8gWd544/SZs01aKT9eI/AAAAAAAAARQ/s3CT6Kt-r8U/s1600-h/InstallerWithOneDependency.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 245px;" src="http://2.bp.blogspot.com/_nWyC8gWd544/SZs01aKT9eI/AAAAAAAAARQ/s3CT6Kt-r8U/s400/InstallerWithOneDependency.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5303891078319175138" /&gt;&lt;/a&gt;&lt;br /&gt;Notice the box beside AssemblyA now contains a checkbox.  As I continue adding projects, each of these will be similarly checked.  Below is an example after all but one assembly has been added.  Even with 149 projects to include, it takes very little time to scan through the list and see which items remain unchecked.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nWyC8gWd544/SZs09HAyXUI/AAAAAAAAARY/oeoIDnJ6HzY/s1600-h/InstallerWithFourDependencies.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 245px;" src="http://4.bp.blogspot.com/_nWyC8gWd544/SZs09HAyXUI/AAAAAAAAARY/oeoIDnJ6HzY/s400/InstallerWithFourDependencies.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5303891210617904450" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-6951306125923861539?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/6951306125923861539/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/02/visual-studio-installer-projects-which.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/6951306125923861539'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/6951306125923861539'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/02/visual-studio-installer-projects-which.html' title='Visual Studio installer projects - which project did I forget to include?'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_nWyC8gWd544/SZs0iMx1CQI/AAAAAAAAAQ4/vRNkmpwtvJY/s72-c/SolutionListing.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-8274322320342974732</id><published>2009-02-11T12:33:00.003-06:00</published><updated>2009-02-11T12:47:42.447-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Subversion'/><title type='text'>Subversion failure to copy file</title><content type='html'>We ran into some difficulty today adding a new project to our build server.  We kept getting an svn error stating:&lt;br /&gt;&lt;br /&gt;"Can't copy 'C:\MyProject\_svn\tmp\text-base\web.config.svn-base' to 'C:\MyProject\_svn\tmp\web.config.tmp.tmp'.&lt;br /&gt;&lt;br /&gt;Not the most helpful of error messages, as I have no knowledge of the inner-workings of svn.  Fortunately, a quick Google search turned up a &lt;a href="http://tortoisesvn.net/node/167" title="Can't copy/move 'XXX.svn-base' to 'XXX.tmp'"&gt;TortoiseSVN FAQ entry&lt;/a&gt; that proved useful.&lt;br /&gt;&lt;br /&gt;In our code repository we had two web.config files in the same directory.  The only difference was one had an initial uppercase 'W' while the second was lowercase.  SVN handles this just fine internally. The problem occurs when you attempt to pull them down to the same location on a Windows machine.  Since Windows ignores casing, these were being treated as the same file. SVN was complaining that the folder didn't contain the second copy of the file. Deleting one of the copies in SVN fixed the build error.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-8274322320342974732?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/8274322320342974732/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/02/subversion-failure-to-copy-file.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8274322320342974732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8274322320342974732'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/02/subversion-failure-to-copy-file.html' title='Subversion failure to copy file'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-7787890765433096752</id><published>2009-01-23T14:30:00.007-06:00</published><updated>2009-08-19T22:33:29.758-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='NUnit'/><title type='text'>Row tests in NUnit</title><content type='html'>[Update 8/19/09: As of version 2.5, the extensions are no longer installed with NUnit. See my post on &lt;a href="http://automaticchainsaw.blogspot.com/2009/08/parameterized-tests-in-nunit.html" title="Parameterized tests in NUnit"&gt;parameterized tests&lt;/a&gt; for a replacement.]&lt;br /&gt;&lt;br /&gt;File this one under "old features I'm only now learning about."  It seems NUnit has had a RowTest extension built in since March of 08...&lt;br /&gt;&lt;br /&gt;For example, let's say I have a method called Add that adds two integers and returns the result.  (The internals of that method are highly complex and I won't go into details here.)  If you wanted to test two positive integers, a unit test would look like this:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;Test&lt;/span&gt;]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; AddTwoPositiveNumbers()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: #2b91af;"&gt;Assert&lt;/span&gt;.AreEqual(2 + 3, Add(2, 3), &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #a31515;"&gt;"Add returned incorrect result"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;To test two negative integers you would historically create a second, nearly identical unit test:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;Test&lt;/span&gt;]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; AddTwoNegativeNumbers()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: #2b91af;"&gt;Assert&lt;/span&gt;.AreEqual(-1 + -4, Add(-1, -4), &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #a31515;"&gt;"Add returned incorrect result"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;For reference, the two tests will appear under the class name when viewed through the NUnit GUI.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_nWyC8gWd544/SXoqKzGEQPI/AAAAAAAAAQw/d9sObu6g6lU/s1600-h/individual_tests.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 59px;" src="http://4.bp.blogspot.com/_nWyC8gWd544/SXoqKzGEQPI/AAAAAAAAAQw/d9sObu6g6lU/s400/individual_tests.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5294590676930150642" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now, these don't seem too bad, but what happens if you needs lots of nearly-identical tests?  Or these tests need to perform additional steps?  Copy/paste is a bad programming practice, even for unit tests.  Fortunately, Nunit provides an extension (under the NUnit.Framework.Extensions namespace not surprisingly) that makes life much easier - the RowTest.&lt;br /&gt;&lt;br /&gt;To use, create a single test method with parameters for the varying test data.  Decorate the method with a RowTest attribute, and one Row attribute for each test case.  The above unit tests can now be replaced by:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;RowTest&lt;/span&gt;]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;Row&lt;/span&gt;(2, 3)]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;[&lt;span style="color: #2b91af;"&gt;Row&lt;/span&gt;(-1, -4)]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; AddTwoNumbers(&lt;span style="color: blue;"&gt;int&lt;/span&gt; x, &lt;span style="color: blue;"&gt;int&lt;/span&gt; y)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: #2b91af;"&gt;Assert&lt;/span&gt;.AreEqual(x + y, Add(x, y), &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: #a31515;"&gt;"Add returned incorrect result"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Changes to the test set becomes much easier, as does adding new tests.  In the GUI, you'll see each Row split out as an individual test beneath the generic test:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_nWyC8gWd544/SXop_msPhwI/AAAAAAAAAQo/6J0fvtKtIUw/s1600-h/row_tests.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 72px;" src="http://2.bp.blogspot.com/_nWyC8gWd544/SXop_msPhwI/AAAAAAAAAQo/6J0fvtKtIUw/s400/row_tests.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5294590484622051074" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-7787890765433096752?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/7787890765433096752/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/01/row-tests-in-nunit.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7787890765433096752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7787890765433096752'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2009/01/row-tests-in-nunit.html' title='Row tests in NUnit'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_nWyC8gWd544/SXoqKzGEQPI/AAAAAAAAAQw/d9sObu6g6lU/s72-c/individual_tests.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-8717424021897291117</id><published>2008-12-12T10:46:00.010-06:00</published><updated>2009-05-21T13:01:25.957-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VS2005'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>Debugging XSL Transformations in VisualStudio 2005</title><content type='html'>I've been doing a bit of work lately with XSL transforms.  While searching for a good transform debugging tool, I found that I had a decent one already installed - VisualStudio. To demonstrate, I pulled sample xml and xslt from the &lt;a href="http://www.w3schools.com/xsl/xsl_if.asp"&gt;W3Schools&lt;/a&gt; site.  (Click on each image to see a larger version.)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nWyC8gWd544/SUKWIqVfWxI/AAAAAAAAAOw/cNQ3Izrl4AM/s1600-h/1_xslt.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 291px;" src="http://2.bp.blogspot.com/_nWyC8gWd544/SUKWIqVfWxI/AAAAAAAAAOw/cNQ3Izrl4AM/s400/1_xslt.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5278946788779186962" /&gt;&lt;/a&gt;&lt;br /&gt;With the xsl template loaded in VS, right-click anywhere on the xslt and choose Properties.  In the Properties window, set the Input value to point to the sample xml file (cdcatalog.xml in this case.)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nWyC8gWd544/SUKWTMNbz9I/AAAAAAAAAO4/wpCiDNpVsks/s1600-h/2_xslt_properties.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 291px;" src="http://4.bp.blogspot.com/_nWyC8gWd544/SUKWTMNbz9I/AAAAAAAAAO4/wpCiDNpVsks/s400/2_xslt_properties.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5278946969670897618" /&gt;&lt;/a&gt;&lt;br /&gt;At this point you can run the transform to view the output.  Choose "XML" &gt; "Debug XSLT" from the menu.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nWyC8gWd544/SUKWdWmSXBI/AAAAAAAAAPA/JFcU8hYcKs4/s1600-h/3_xslt_output.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 291px;" src="http://4.bp.blogspot.com/_nWyC8gWd544/SUKWdWmSXBI/AAAAAAAAAPA/JFcU8hYcKs4/s400/3_xslt_output.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5278947144258182162" /&gt;&lt;/a&gt;&lt;br /&gt;Nothing terribly interesting so far.  The real fun doesn't start until you realize you can set breakpoints within the xslt.  This is done the same as with other types of code files (by clicking the grey strip on the left or pressing F9.)  Now, when you start the debugger, processing stops at the specified line.  As expected, hovering the mouse over a variable or expression gives you a tooltip with the value.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_nWyC8gWd544/SUKWkNUQsvI/AAAAAAAAAPI/yN6U6aVsHtY/s1600-h/4_xslt_breakpoint.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 291px;" src="http://1.bp.blogspot.com/_nWyC8gWd544/SUKWkNUQsvI/AAAAAAAAAPI/yN6U6aVsHtY/s400/4_xslt_breakpoint.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5278947262025741042" /&gt;&lt;/a&gt;&lt;br /&gt;Several of the other debug windows are also usable in this mode, such as the Locals and Immediate window.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_nWyC8gWd544/SUKWqZg6zDI/AAAAAAAAAPQ/eLizxoUsqoU/s1600-h/5_xslt_locals.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 291px;" src="http://4.bp.blogspot.com/_nWyC8gWd544/SUKWqZg6zDI/AAAAAAAAAPQ/eLizxoUsqoU/s400/5_xslt_locals.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5278947368379272242" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_nWyC8gWd544/SUKW1-GGmiI/AAAAAAAAAPY/8l06Aw3gTd4/s1600-h/6_xslt_immediate.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 291px;" src="http://2.bp.blogspot.com/_nWyC8gWd544/SUKW1-GGmiI/AAAAAAAAAPY/8l06Aw3gTd4/s400/6_xslt_immediate.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5278947567177472546" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-8717424021897291117?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/8717424021897291117/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/12/debugging-xsl-transformations-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8717424021897291117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8717424021897291117'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/12/debugging-xsl-transformations-in.html' title='Debugging XSL Transformations in VisualStudio 2005'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_nWyC8gWd544/SUKWIqVfWxI/AAAAAAAAAOw/cNQ3Izrl4AM/s72-c/1_xslt.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-4462811474868240107</id><published>2008-12-11T14:52:00.002-06:00</published><updated>2008-12-11T15:03:22.127-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>New Year's Resolutions</title><content type='html'>I was looking through my "to blog" list recently and I was reminded of something:  I have a LOT of items on my list.  Two or three times the number of posts I've written thus far.  What's worse is some of these items would actually make an entire series of posts.  At my current rate of posting (once or twice a month) I'm never going to finish.&lt;br /&gt; &lt;br /&gt;Then there are the computer books sitting on my shelf, several of which I've not read much passed the intro.  Some may not be worth digging into right now, but a few of them are "must reads."  &lt;a href="http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670"&gt;Code Complete&lt;/a&gt; for example.  Or &lt;a href="http://www.amazon.com/First-Design-Patterns-Elisabeth-Freeman/dp/0596007124/"&gt;Head First Design Patterns&lt;/a&gt;.  I've not finished either of them, and have yet to fully grok what I have read.&lt;br /&gt; &lt;br /&gt;The question then is how to tackle these lists?  It seems the only way to stay motivated is to come up with a schedule and then stick to it.  Read one chapter a week.  Write a blog post a week.  Or if I work it just right, I could write a blog post on the chapter I just read.  But what if I get bored with one subject?  Do I switch between books each week, or should I stick to one until I finish?  If I want to post on what I'm reading, how much original content is necessary and how much can I quote or link to?&lt;br /&gt;&lt;br /&gt;I'm off to ponder these questions (or read &lt;a href="http://www.giantitp.com/comics/ootscast.html"&gt;web comics&lt;/a&gt;, I've not decided which.)  What are your thoughts on the subject?  Do you have any professional goals to tackle next year?  (Or even non-professional goals?)  And if so, how do you plan to keep on track?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-4462811474868240107?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/4462811474868240107/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/12/new-years-resolutions.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/4462811474868240107'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/4462811474868240107'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/12/new-years-resolutions.html' title='New Year&apos;s Resolutions'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-7351778818756552042</id><published>2008-11-18T10:01:00.003-06:00</published><updated>2008-11-18T10:14:56.544-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>Batch permission change for MSSQL stored procs</title><content type='html'>I recently ran into a batch of existing stored procs that needed additional execute permissions.  After some digging on the web I was able to put together a simple script to make the changes.  Since I'll likely need it again in the future, I decided to throw it out here.&lt;br /&gt;&lt;br /&gt;Assuming all of the stored procs contain the string 'MyApp' in the name, and all need execute permissions added for 'myuser', the following will make the necessary change&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;declare &lt;/span&gt;@SQL &lt;span style="color: blue;"&gt;varchar&lt;/span&gt;(8000)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;select &lt;/span&gt;@SQL = &lt;span style="color: blue;"&gt;isnull&lt;/span&gt;(@SQL, &lt;span style="color: #a31515;"&gt;''&lt;/span&gt;) + &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: #a31515;"&gt;'grant execute on [' &lt;/span&gt;+ &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; routine_schema + &lt;span style="color: #a31515;"&gt;'].[' &lt;/span&gt;+ &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; routine_name + &lt;span style="color: #a31515;"&gt;'] to [myuser];'&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;from &lt;/span&gt;information_schema.routines &lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;where &lt;/span&gt;SPECIFIC_NAME &lt;span style="color: blue;"&gt;like &lt;/span&gt;&lt;span style="color: #a31515;"&gt;'%MyApp%' &lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;exec &lt;/span&gt;(@SQL )&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-7351778818756552042?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/7351778818756552042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/11/batch-permission-change-for-mssql.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7351778818756552042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7351778818756552042'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/11/batch-permission-change-for-mssql.html' title='Batch permission change for MSSQL stored procs'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-7143265702369286500</id><published>2008-09-11T20:51:00.010-05:00</published><updated>2009-09-21T10:47:31.451-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='refactoring'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Refactor - Moving duplicate code to a separate method</title><content type='html'>I've mentioned in previous posts that it pains me to see developers use copy/paste to write code.  It's more error prone, as you have to make sure all necessary changes are made to the copy.  It's also harder to maintain since finding a bug in one copy of the code means making changes to the others - assuming you can find those copies.  Depending on the circumstances, it can also be harder to read the code.  As I keep running into less-than-ideal code, I decided a few posts were in order.&lt;br /&gt;&lt;br /&gt;Today, let's look at a method that builds an XmlDocument based on values from a database.  Here, the info is passed in a DataRow object.&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 8pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;XmlDocument&lt;/span&gt; GenerateMailingLabel(&lt;span style="color: #2b91af;"&gt;DataRow&lt;/span&gt; subscriber)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;XmlDocument&lt;/span&gt; doc = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;XmlDocument&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; doc.LoadXml(&lt;span style="color: #a31515;"&gt;"&amp;lt;MailingLabel&amp;gt;&amp;lt;SendTo /&amp;gt;&amp;lt;/MailingLabel&amp;gt;"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;XmlNode&lt;/span&gt; sendToNode = doc.SelectSingleNode(&lt;span style="color: #a31515;"&gt;"//SendTo"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;XmlAttribute&lt;/span&gt; attribute = doc.CreateAttribute(&lt;span style="color: #a31515;"&gt;"FirstName"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; attribute.Value = subscriber[&lt;span style="color: #a31515;"&gt;"FirstName"&lt;/span&gt;].ToString();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; sendToNode.Attributes.Append(attribute);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; attribute = doc.CreateAttribute(&lt;span style="color: #a31515;"&gt;"LastName"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; attribute.Value = subscriber[&lt;span style="color: #a31515;"&gt;"LastName"&lt;/span&gt;].ToString();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; sendToNode.Attributes.Append(attribute);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; attribute = doc.CreateAttribute(&lt;span style="color: #a31515;"&gt;"StreetAddress"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; attribute.Value = subscriber[&lt;span style="color: #a31515;"&gt;"StreetAddress"&lt;/span&gt;].ToString();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; sendToNode.Attributes.Append(attribute);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; attribute = doc.CreateAttribute(&lt;span style="color: #a31515;"&gt;"City"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; attribute.Value = subscriber[&lt;span style="color: #a31515;"&gt;"City"&lt;/span&gt;].ToString();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; sendToNode.Attributes.Append(attribute);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; attribute = doc.CreateAttribute(&lt;span style="color: #a31515;"&gt;"State"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; attribute.Value = subscriber[&lt;span style="color: #a31515;"&gt;"State"&lt;/span&gt;].ToString();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; sendToNode.Attributes.Append(attribute);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; attribute = doc.CreateAttribute(&lt;span style="color: #a31515;"&gt;"Zip"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; attribute.Value = subscriber[&lt;span style="color: #a31515;"&gt;"Zip"&lt;/span&gt;].ToString();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; sendToNode.Attributes.Append(attribute);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; doc;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;There's nothing terribly complex going on here.  It starts by creating a new, nearly empty XmlDocument.  It then pulls necessary values out of the DataRow and adds them as attributes to the &amp;lt;SendTo&amp;gt; node.  Modifying existing attributes appears to be easy, as each one is isolated to a single block of three lines.  Adding new attributes is similarly straightforward.  Copy an existing block, paste it just before the 'return', and then modify the two string literals.  If it's so easy to work with, why change the code?&lt;br /&gt;&lt;br /&gt;First, you have to make sure you modify both string literals correctly.  Fail to modify one or both of them and you have a bug that may not be caught any time soon.&lt;br /&gt;&lt;br /&gt;Second, these types of methods tend to become long.  It may be easy to read currently, but what happens when you have twenty attributes to add to the document?  Picking out a particular block to modify becomes a bit more challenging.  This is especially true if you're currently lacking in sleep and/or caffein.&lt;br /&gt;&lt;br /&gt;Third, a structural change to the xml document becomes a slow, tedious task.  Maybe halfway through the project someone decides you need to create sub-elements instead of attributes for each value.  In the above code, you have six sets of changes to make.&lt;br /&gt;&lt;br /&gt;A better solution would be to pull the block of three lines into a separate method:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 8pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;private&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; CreateAttribute(&lt;span style="color: blue;"&gt;string&lt;/span&gt; attributeName, &lt;span style="color: blue;"&gt;string&lt;/span&gt; columnName,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;XmlDocument&lt;/span&gt; doc, &lt;span style="color: #2b91af;"&gt;XmlNode&lt;/span&gt; sendToNode, &lt;span style="color: #2b91af;"&gt;DataRow&lt;/span&gt; subscriber)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;XmlAttribute&lt;/span&gt; attribute = doc.CreateAttribute(attributeName);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; attribute.Value = subscriber[columnName].ToString();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; sendToNode.Attributes.Append(attribute);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Once we've done this, each block of code in the GenerateMailingLabel method can be reduced to a single line:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 8pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;XmlDocument&lt;/span&gt; GenerateMailingLabel(&lt;span style="color: #2b91af;"&gt;DataRow&lt;/span&gt; subscriber)&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;XmlDocument&lt;/span&gt; doc = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;XmlDocument&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; doc.LoadXml(&lt;span style="color: #a31515;"&gt;"&amp;lt;MailingLabel&amp;gt;&amp;lt;SendTo /&amp;gt;&amp;lt;/MailingLabel&amp;gt;"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: #2b91af;"&gt;XmlNode&lt;/span&gt; sendToNode = doc.SelectSingleNode(&lt;span style="color: #a31515;"&gt;"//SendTo"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; CreateAttribute(&lt;span style="color: #a31515;"&gt;"FirstName"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"FirstName"&lt;/span&gt;, doc,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; sendToNode, subscriber);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; CreateAttribute(&lt;span style="color: #a31515;"&gt;"LastName"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"LastName"&lt;/span&gt;, doc,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; sendToNode, subscriber);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; CreateAttribute(&lt;span style="color: #a31515;"&gt;"StreetAddress"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"StreetAddress"&lt;/span&gt;, doc,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; sendToNode, subscriber);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; CreateAttribute(&lt;span style="color: #a31515;"&gt;"City"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"City"&lt;/span&gt;, doc,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; sendToNode, subscriber);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; CreateAttribute(&lt;span style="color: #a31515;"&gt;"State"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"State"&lt;/span&gt;, doc,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; sendToNode, subscriber);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; CreateAttribute(&lt;span style="color: #a31515;"&gt;"Zip"&lt;/span&gt;, &lt;span style="color: #a31515;"&gt;"Zip"&lt;/span&gt;, doc,&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; sendToNode, subscriber);&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; doc;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Now adding a new attribute requires one additional line instead of three.  Even better, bug fixes or structural changes will be limited to a single section of code.  In either case, changes can be made faster and with less risk of introducing bugs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-7143265702369286500?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/7143265702369286500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/09/refactor-moving-duplicate-code-to_2138.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7143265702369286500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7143265702369286500'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/09/refactor-moving-duplicate-code-to_2138.html' title='Refactor - Moving duplicate code to a separate method'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-2856412152142082555</id><published>2008-08-29T16:22:00.005-05:00</published><updated>2008-08-29T16:33:15.161-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Verify user membership in an AD group</title><content type='html'>Occasionally, when working on a WinForms application, I need to validate the current user against an Active Directory group before letting the application run.  Though not a complex task, it usually takes me a bit of time to research (Translation: I have to copy code from several web sites and modify to suit my needs.)  So I figured I'd post my own implementation here for others to use in their research.  That, and maybe save myself a bit of time in the future.&lt;br /&gt;&lt;br /&gt;The first step is to get the list of AD groups the current user belongs to.  The magic necessary to make this happen is contained in the System.DirectoryServices namespace.  The code to return the list looks like so:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;internal&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; GetADGroupsForCurrentUser()&lt;br /&gt;{&lt;br /&gt;    List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; groups = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;();&lt;br /&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; domainName = Environment.UserDomainName;&lt;br /&gt;    DirectoryEntry entry = &lt;span class="kwrd"&gt;new&lt;/span&gt; DirectoryEntry(&lt;span class="str"&gt;"LDAP://"&lt;/span&gt;&lt;br /&gt;          + domainName);&lt;br /&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; filter = &lt;span class="str"&gt;"(samAccountName="&lt;/span&gt;&lt;br /&gt;          + Environment.UserName + &lt;span class="str"&gt;")"&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;    DirectorySearcher search = &lt;br /&gt;          &lt;span class="kwrd"&gt;new&lt;/span&gt; DirectorySearcher(entry, filter);&lt;br /&gt;    search.PropertiesToLoad.Add(&lt;span class="str"&gt;"memberOf"&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;    SearchResult results = search.FindOne();&lt;br /&gt;    &lt;span class="kwrd"&gt;int&lt;/span&gt; groupsCount = results.Properties.Count;&lt;br /&gt;    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; groupsCount; i++)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; groupString = &lt;br /&gt;            results.Properties[&lt;span class="str"&gt;"memberOf"&lt;/span&gt;][i].ToString();&lt;br /&gt;        groups.Add(groupString);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; groups;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Once we have the list, we need to loop through it looking for the desired AD group.  The strings returned from the above code contain comma-delimited properties (something like "CN=MyDomainGroup,OU=Security Groups,DC=local".)  Because of this I'm using the Contains method to search the string for the desired domain name.  I'm sure there's another way to do this, but whatever works...&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&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; CurrentUserIsAuthorized(&lt;span class="kwrd"&gt;string&lt;/span&gt; authorizedGroupName)&lt;br /&gt;{&lt;br /&gt;    List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; activeDirectoryGroups =&lt;br /&gt;          GetADGroupsForCurrentUser();&lt;br /&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; group &lt;span class="kwrd"&gt;in&lt;/span&gt; activeDirectoryGroups)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (group.Contains(authorizedGroupName))&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&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/6566548306419873706-2856412152142082555?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/2856412152142082555/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/08/verify-user-membership-in-ad-group.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2856412152142082555'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2856412152142082555'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/08/verify-user-membership-in-ad-group.html' title='Verify user membership in an AD group'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-5525898353632748548</id><published>2008-08-27T09:17:00.003-05:00</published><updated>2008-08-27T09:25:39.579-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VS2005'/><title type='text'>Intellisense for WCF config files</title><content type='html'>I found it slightly irritating that there is no intellisense for WCF config files built into VS2005.  Fortunately a quick Google search turned up a blog post with a solution.  I figured I'd post it here so I can find it later.  That, plus it allows me to meet my self-imposed quota of at least one blog entry per month  :)&lt;br /&gt;&lt;br /&gt;The solution can be found &lt;a href="http://blogs.msdn.com/govindr/archive/2007/03/06/using-visual-studio-intellisense-to-edit-wcf-configuration-files.aspx"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-5525898353632748548?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/5525898353632748548/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/08/intellisense-for-wcf-config-files.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/5525898353632748548'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/5525898353632748548'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/08/intellisense-for-wcf-config-files.html' title='Intellisense for WCF config files'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-8673592309270309780</id><published>2008-07-13T14:17:00.005-05:00</published><updated>2008-11-13T07:50:42.834-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VS2005'/><title type='text'>Don't make me GAC</title><content type='html'>We discovered an interesting "feature" in VisualStudio 2005 a couple days ago.  Let's say I have a solution containing a Utilities project and a web site referencing that project.  The Utilities assembly references a third-party dll (log4net in this case.)  When the web site is compiled, it automatically pulls any dependent files into its 'bin' folder.  Note the presence of log4net.dll&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_nWyC8gWd544/SHpVPIib9fI/AAAAAAAAAJs/XX0hZlwV8pQ/s1600-h/dll_present.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_nWyC8gWd544/SHpVPIib9fI/AAAAAAAAAJs/XX0hZlwV8pQ/s400/dll_present.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5222580436367832562" /&gt;&lt;/a&gt;&lt;br /&gt;This seems fairly straightforward.  But let's say I then load the solution on another computer (a build server perhaps.)  The code compiles as before, but this time it doesn't pull in log4net.dll&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_nWyC8gWd544/SHpVYxEBAGI/AAAAAAAAAJ0/H3QjuTQcL5Q/s1600-h/dll_missing.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_nWyC8gWd544/SHpVYxEBAGI/AAAAAAAAAJ0/H3QjuTQcL5Q/s400/dll_missing.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5222580601864912994" /&gt;&lt;/a&gt;&lt;br /&gt;At this point, I could manually copy the dll into the folder, right?  That was my first thought, which of course proved to be wrong.  The reason is that we also have an install project for the site.  The installer is set to use all output files from the web project.  If we add files to the site, the installer will automatically include them in the next compile.  Unfortunately, when I manually add the dll to the bin folder, the installer overlooks it.&lt;br /&gt;&lt;br /&gt;My next thought was to directly reference the log4net.dll in the web project.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_nWyC8gWd544/SHpVxRi8dcI/AAAAAAAAAKE/Q_9PIDsxqXg/s1600-h/dll_bin_ref(small).bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_nWyC8gWd544/SHpVxRi8dcI/AAAAAAAAAKE/Q_9PIDsxqXg/s400/dll_bin_ref(small).bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5222581022901433794" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Which still compiles on my box.  And still ignores the dll on the build server.  At this point, we opened up the references dialog on the build box.  Much to our surprise, the dll is being referenced in the GAC&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_nWyC8gWd544/SHpWIXekGOI/AAAAAAAAAKM/51IRV4udazo/s1600-h/dll_gac_ref(small).bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_nWyC8gWd544/SHpWIXekGOI/AAAAAAAAAKM/51IRV4udazo/s400/dll_gac_ref(small).bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5222581419630663906" /&gt;&lt;/a&gt;&lt;br /&gt;It seems that when a web project loads, it first looks in the GAC for referenced assemblies.  If it finds them there, it ignores the files originally pointed to.  Because of this, VisStudio doesn't copy the files to the bin folder.  Which of course means the installer won't contain the dll.&lt;br /&gt;&lt;br /&gt;Ideally, the dll shouldn't have been GAC'd on the build server.  Since removing it from the GAC would cause us other issues, our workaround was to hard-code log4net.dll in the install project.&lt;br /&gt;&lt;br /&gt;Note: The web site was built using the out-of-the-box project template, which doesn't create an actual .proj file.  Microsoft later released a Web Application Project (with VS2005 SP1) that does create a .proj.  It's possible that this would force the dll to load from the file reference, but I've not tested that theory.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-8673592309270309780?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/8673592309270309780/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/07/dont-make-me-gac.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8673592309270309780'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8673592309270309780'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/07/dont-make-me-gac.html' title='Don&apos;t make me GAC'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_nWyC8gWd544/SHpVPIib9fI/AAAAAAAAAJs/XX0hZlwV8pQ/s72-c/dll_present.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-8249124543054518559</id><published>2008-06-22T14:31:00.006-05:00</published><updated>2008-06-22T14:43:18.433-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Wrapping a class in a singleton</title><content type='html'>My current task at work has me building a new application, using an existing framework as the base.  One of the classes in this framework wraps access to the config file (which is actually kept in the database.)  As soon as this class is instantiated, it retrieves the config info from the database.  I wanted a way to keep a single instance around for the lifetime of the application.  Otherwise, I'd be hitting the database multiple times to pull down the same information.&lt;br /&gt;&lt;br /&gt;One option would have been to create an instance in the app's constructor.  The downside to that approach is that I'd have to pass it into every method that might need it.  Instead I chose to use the &lt;a href="http://en.wikipedia.org/wiki/Singleton_pattern"&gt;singleton pattern&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Below is a quick example.  Marking the MyConfig class as static means it can't be instantiated.  The static constructor will be called once and only once - the first time the class is accessed.  This constructor creates an instance of the CommonConfig class, which can be accessed through the Config property.  Now, regardless of how many times my code accesses MyConfig.Config, the database is only hit once.&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;MyConfig&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: blue;"&gt;readonly&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;CommonConfig&lt;/span&gt; _commonConfig;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;static&lt;/span&gt; MyConfig()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; _commonConfig = &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;CommonConfig&lt;/span&gt;();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;static&lt;/span&gt; &lt;span style="color: #2b91af;"&gt;CommonConfig&lt;/span&gt; Config&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;get&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;return&lt;/span&gt; _commonConfig;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-8249124543054518559?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/8249124543054518559/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/06/wrapping-class-in-singleton.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8249124543054518559'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8249124543054518559'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/06/wrapping-class-in-singleton.html' title='Wrapping a class in a singleton'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-1173339428536574052</id><published>2008-05-09T14:04:00.002-05:00</published><updated>2008-05-09T14:14:20.711-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>Add scroll wheel support to VB6</title><content type='html'>Yes, you read that right.  The client I'm currently assigned to has a significant amount of legacy code in VB6.  Not an ideal situation, but at least it isn't COBOL.&lt;br /&gt;&lt;br /&gt;Anyway, one of the first things I noticed after loading a project was that I couldn't scroll through the code using the mouse wheel.  It turns out the VB6 IDE didn't include wheel support.  Fortunately, there's an add-in from Microsoft that fixes this.  See &lt;a href="http://support.microsoft.com/kb/837910" title="Mouse wheel events do not work in the Visual Basic 6.0 IDE"&gt;KB article 837910&lt;/a&gt; for the download and install instructions.&lt;br /&gt;&lt;br /&gt;And yes, I'm aware that this probably doesn't pertain to you (if it does, I feel your pain.)  The post is mainly a bookmark for my own reference.  Any sympathy it generates is just a bonus  :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-1173339428536574052?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/1173339428536574052/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/05/add-scroll-wheel-support-to-vb6.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1173339428536574052'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1173339428536574052'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/05/add-scroll-wheel-support-to-vb6.html' title='Add scroll wheel support to VB6'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-700591674006549699</id><published>2008-05-08T12:29:00.002-05:00</published><updated>2008-05-08T12:52:55.979-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>DotNetMigrations</title><content type='html'>A friend of mine recently ported the Ruby on Rails "Migrations" tool to .Net.  Assuming you can get all of the developers on a team to script out their database changes (and matching rollbacks) this tool will make it easier to build, update and deploy your database.  It also becomes trivial to revert the changes when something breaks unexpectedly.&lt;br /&gt;&lt;br /&gt;You can find details &lt;a href="http://www.codeplex.com/dotnetmigrations" title="DotNetMigrations on CodePlex"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-700591674006549699?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/700591674006549699/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/05/dotnetmigrations.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/700591674006549699'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/700591674006549699'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/05/dotnetmigrations.html' title='DotNetMigrations'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-2115389013648802160</id><published>2008-05-08T10:32:00.005-05:00</published><updated>2008-11-13T07:50:43.361-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>Adding entries to a file's right-click menu</title><content type='html'>When setting up a new developer computer, there are a number of tools and shortcuts I typically want.  One of these is the ability to register COM dlls through Explorer's right-click menu.  The easiest way to add this is through the registry.&lt;br /&gt;&lt;br /&gt;Standard warning: I'm sure you're aware that messing with the registry may cause all sorts of problems.  Proceed with caution.  Unless of course it's not your computer you're messing with.  In which case, hack away.&lt;br /&gt;&lt;br /&gt;Start regedit from the Run dialog (keyboard shortcut: Win+R.)  Under HKCR (HKEY_CLASSES_ROOT) locate the extension of the file to modify - .dll in this case.  In the list of properties, you should see a "(Default)" string with the internal name of the file type.  For dll it will be "dllfile."&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_nWyC8gWd544/SCMdVOMXpRI/AAAAAAAAAI0/GiEeYg8zm_c/s1600-h/dll.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_nWyC8gWd544/SCMdVOMXpRI/AAAAAAAAAI0/GiEeYg8zm_c/s400/dll.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5198030645340120338" /&gt;&lt;/a&gt;&lt;br /&gt;Further down, still under HKCR, will be an entry for dllfile.  This is where the changes will be made.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_nWyC8gWd544/SCMddeMXpSI/AAAAAAAAAI8/zqEaxgcBL2I/s1600-h/dllfile.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_nWyC8gWd544/SCMddeMXpSI/AAAAAAAAAI8/zqEaxgcBL2I/s400/dllfile.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5198030787074041122" /&gt;&lt;/a&gt;&lt;br /&gt;Under dllfile, expand the "shell" key.  Add a new key and set the name as you want it to appear on the right-click menu (mine is "register".)  Within that, add another key with the value "command."  The "(Default)" string needs be set to the command that you want to run.  For this exercise it will be:&lt;br /&gt;&lt;br /&gt;regsvr32.exe "%1"&lt;br /&gt;&lt;br /&gt;Regsvr32 is the command-line utility to register the COM component.  The %1 in quotes tells Windows to pass in the filename and path as the first parameter.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_nWyC8gWd544/SCMdkOMXpTI/AAAAAAAAAJE/p2iPoEwjw_8/s1600-h/register+in+registry.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_nWyC8gWd544/SCMdkOMXpTI/AAAAAAAAAJE/p2iPoEwjw_8/s400/register+in+registry.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5198030903038158130" /&gt;&lt;/a&gt;&lt;br /&gt;Once this is done, you should be able to right-click on any dll and see the new entry.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_nWyC8gWd544/SCMdt-MXpUI/AAAAAAAAAJM/ArzMHHsZsGo/s1600-h/register+on+right-click.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_nWyC8gWd544/SCMdt-MXpUI/AAAAAAAAAJM/ArzMHHsZsGo/s400/register+on+right-click.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5198031070541882690" /&gt;&lt;/a&gt;&lt;br /&gt;This takes care of one machine.  Now that you have the shortcut defined, it would be useful to copy this to other machines.  To do so, right-click on the "register" key and choose Export.  Saving the selected branch will give you a .reg file with the changes.  Copy the file to another computer and double-click to import it into the registry of that computer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-2115389013648802160?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/2115389013648802160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/05/adding-entries-to-files-right-click.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2115389013648802160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2115389013648802160'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/05/adding-entries-to-files-right-click.html' title='Adding entries to a file&apos;s right-click menu'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nWyC8gWd544/SCMdVOMXpRI/AAAAAAAAAI0/GiEeYg8zm_c/s72-c/dll.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-7355206192137344326</id><published>2008-05-02T10:01:00.008-05:00</published><updated>2008-11-13T07:50:43.794-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VS2005'/><title type='text'>Metadata? But the code's right there...</title><content type='html'>Here's a highly complex bit of code I've been working on&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_nWyC8gWd544/SBsv57XEOzI/AAAAAAAAAH0/JnUYOVNqVBM/s1600-h/BasicCode.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_nWyC8gWd544/SBsv57XEOzI/AAAAAAAAAH0/JnUYOVNqVBM/s400/BasicCode.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5195799267335486258" /&gt;&lt;/a&gt;&lt;br /&gt;In this example I have a Customer class in MyAssembly2, which you can see is a separate project in the solution.  On the main form of the application I'm making a call to the Customer instance method SaveToDatabase.  If I right-click on the method call and choose "Go To Definition" I'm taken to a page of metadata.  &lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_nWyC8gWd544/SBst97XEOvI/AAAAAAAAAHU/pyAj6K7eq8I/s1600-h/Customer+%5Bfrom+metadata%5D.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_nWyC8gWd544/SBst97XEOvI/AAAAAAAAAHU/pyAj6K7eq8I/s320/Customer+%5Bfrom+metadata%5D.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5195797137031707378" /&gt;&lt;/a&gt;&lt;br /&gt;This lets me see method signatures but not the code within those methods.  If I were to try the same thing for my Utilities class, however, I'm taken to the .cs file within MyAssembly1.  So what's the difference?&lt;br /&gt;&lt;br /&gt;Here are the reference properties for the two assemblies:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_nWyC8gWd544/SBswO7XEO0I/AAAAAAAAAH8/c6L-cirzeOY/s1600-h/assembly+refs.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_nWyC8gWd544/SBswO7XEO0I/AAAAAAAAAH8/c6L-cirzeOY/s400/assembly+refs.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5195799628112739138" /&gt;&lt;/a&gt;&lt;br /&gt;The two are almost identical, but if you look closely, you'll see that MyAssembly2 has a "Specific Version" property where MyAssembly1 does not.  This is because MyAssembly2 was added as a file reference - we pointed VisualStudio at the compiled dll instead of the project.  Because of this, VS doesn't know that the dll and project are really one and the same.&lt;br /&gt;&lt;br /&gt;The fix is a simple matter of deleting the reference to MyAssembly2 and re-adding - this time as a project reference.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-7355206192137344326?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/7355206192137344326/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/05/metadata-but-codes-right-there.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7355206192137344326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7355206192137344326'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/05/metadata-but-codes-right-there.html' title='Metadata? But the code&apos;s right there...'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nWyC8gWd544/SBsv57XEOzI/AAAAAAAAAH0/JnUYOVNqVBM/s72-c/BasicCode.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-8017016055226138493</id><published>2008-04-29T11:20:00.001-05:00</published><updated>2008-04-29T13:53:05.487-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VS2005'/><title type='text'>Everyone should be good at something</title><content type='html'>Anyone who's worked with me in recent years knows how much I love deleting code.  It could be removing something that's obsolete or refactoring to reduce duplication.  Or maybe the requirements change mid-project.  Needless to say, some question whether my SLOC (source lines of code) output is positive or negative.&lt;br /&gt;&lt;br /&gt;Regardless, I stumbled upon a shortcut in VisualStudio (Shift + Del) that deletes the entire line where the cursor is located.  No more selecting the whole line and then pressing Delete.  I've become a code-deletion ninja!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-8017016055226138493?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/8017016055226138493/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/04/everyone-should-be-good-at-something.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8017016055226138493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8017016055226138493'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/04/everyone-should-be-good-at-something.html' title='Everyone should be good at something'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-6364077248160942436</id><published>2008-03-14T11:07:00.002-05:00</published><updated>2008-11-13T07:50:43.955-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='VS2005'/><title type='text'>Unlocking files when Visual Studio can't</title><content type='html'>There's an option in Visual Studio that, on compile, will pull all of your XML comments out into separate files.  These can then be combined into a help file using a tool like &lt;a href="http://msdn2.microsoft.com/en-us/vstudio/bb608422.aspx"&gt;Sandcastle&lt;/a&gt;.  Most of the time this feature works correctly.  If you cancel a build in process, or the compile fails, VS occasionally fails to release the file lock.  From that point on, the compile fails with an error stating the file is in use by another process.  I've not found a way within VS to force an unlock short of closing the app.&lt;br /&gt;&lt;br /&gt;There is, however, a faster way using &lt;a href="http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx"&gt;Process Explorer&lt;/a&gt;.  Start Process Explorer and select Find &amp;gt; Find Handle or DLL... from the menu.  Enter all or part of the filename currently locked, then click Search.  You should see the guilty process - devenv.exe in this case.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_nWyC8gWd544/R9qjQW0DjdI/AAAAAAAAAHE/zFRajcTpktQ/s1600-h/find+handle+dialog.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_nWyC8gWd544/R9qjQW0DjdI/AAAAAAAAAHE/zFRajcTpktQ/s400/find+handle+dialog.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5177630223012957650" /&gt;&lt;/a&gt;&lt;br /&gt;Double-clicking on the entry will display a list of handles for that app, with the selected handle highlighted.  Right-click on the selection and choose Close Handle.  You'll see a dialog warning about potential crashes or system instability (meaning don't try this with a system file.)  Tell it to continue and the handle will be closed.  VS will again compile without issue.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-6364077248160942436?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/6364077248160942436/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/03/unlocking-files-when-visual-studio-cant.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/6364077248160942436'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/6364077248160942436'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/03/unlocking-files-when-visual-studio-cant.html' title='Unlocking files when Visual Studio can&apos;t'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nWyC8gWd544/R9qjQW0DjdI/AAAAAAAAAHE/zFRajcTpktQ/s72-c/find+handle+dialog.bmp' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-152470695750715387</id><published>2008-02-26T09:11:00.003-06:00</published><updated>2008-02-26T09:18:54.731-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>I can read the file myself, thank you</title><content type='html'>I've been downloading a number of PDFs lately, and the one thing that has been bugging me is the slow performance of &lt;a href="http://www.adobe.com/products/acrobat/readstep2.html"&gt;Adobe Reader&lt;/a&gt;.  Fortunately, I've found at least one of the major causes - the accessibility features.  When opening a PDF, I was occasionally presented with a dialog stating "Please wait while the document is being prepared for reading."  A quick search on the web located others with the same problem.  &lt;a href="http://jtbworld.blogspot.com/2007/03/adobe-reader-8-please-wait.html" title="Adobe Reader 8 please wait"&gt;This post&lt;/a&gt;, along with one of the comments, led me to the solution:&lt;br /&gt;&lt;br /&gt;Locate the install folder (C:\Program Files\Adobe\Reader 8.0\Reader\plug_ins) and delete the following files&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Accessibility.api&lt;/li&gt;&lt;br /&gt;&lt;li&gt;MakeAccessible.api&lt;/li&gt;&lt;br /&gt;&lt;li&gt;ReadOutLoud.api&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Though I didn't break out the stopwatch, the performance improvement was significant.  Before, there would be a pause after scrolling more than a page or two.  Now, I can hold the PageDown key and see dozens of pages fly by before any pause (probably to allocate more memory.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-152470695750715387?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/152470695750715387/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/02/i-can-read-file-myself-thank-you.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/152470695750715387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/152470695750715387'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/02/i-can-read-file-myself-thank-you.html' title='I can read the file myself, thank you'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-5255401319577312585</id><published>2008-02-12T09:59:00.000-06:00</published><updated>2008-02-26T09:19:29.524-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Automate config changes for different environments</title><content type='html'>Most applications I've worked on contain one or more config files.  These are generally used to track web service locations, database connection strings, and logging information.  Keeping these settings outside the code makes it easy to modify them without a recompile.  This is especially useful when moving a deployment from dev to test, or from test to production.&lt;br /&gt;&lt;br /&gt;On most of these projects, the preferred method used by developers is to keep multiple config files in the source repository.  These are distinguished by simple renaming of the files (such as app.config, app_qa.config, app_prod.config.)  In theory this should work - once you have the config files set up for each environment, deployment requires replacing the file as appropriate.  And if you use a .bat file or build script, the file rename will be automatic.&lt;br /&gt;&lt;br /&gt;The scenario usually overlooked, however, is the case where something in the config changes.  Maybe a new web service is being used by the application.  Or perhaps a new assembly needs to be referenced.  In my experience, the developer often makes the changes to the main file (app.config), but forgets to make the same changes to the others.  During development the code appears to work fine.  Unfortunately, the app fails to run in the QA environment.  Usually, some amount of time is spent by the developer before realizing that the problem is with the config.&lt;br /&gt;&lt;br /&gt;To reduce this sort of issue, I recommend only keeping one config in the source repository.  This config will contain the values necessary to run in the development environment.  During the build process, the config is updated for the target environment.  The &lt;a href="http://msbuildtasks.tigris.org/"&gt;MSBuild Community Tasks&lt;/a&gt; contains a FileUpdate task that makes this easy.&lt;br /&gt;&lt;br /&gt;Let's say you have a config file with the following:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;appSettings&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;add&lt;/span&gt; &lt;span class="attr"&gt;key&lt;/span&gt;&lt;span class="kwrd"&gt;="MyWebService"&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="http://localhost/service/MyWebService.asmx"&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;appSettings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;The msbuild script to deploy to QA would contain:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&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;MyAppConfigFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;c:\source\MyApp\app.config&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;MyAppConfigFile&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;MyWebServiceRegex&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;http://.*/service/MyWebService.asmx&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;MyWebServiceRegex&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;QaWebServicePath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;http://QaServer/service/MyWebService.asmx&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;QaWebServicePath&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;PropertyGroup&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;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="ConfigureQA"&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;FileUpdate&lt;/span&gt;&lt;br /&gt;       &lt;span class="attr"&gt;Files&lt;/span&gt;&lt;span class="kwrd"&gt;="$(MyAppConfigFile)"&lt;/span&gt;&lt;br /&gt;       &lt;span class="attr"&gt;Regex&lt;/span&gt;&lt;span class="kwrd"&gt;="$(MyWebServiceRegex)"&lt;/span&gt;&lt;br /&gt;       &lt;span class="attr"&gt;ReplacementText&lt;/span&gt;&lt;span class="kwrd"&gt;="$(QaWebServicePath)"&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;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-5255401319577312585?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/5255401319577312585/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/02/automate-config-changes-for-different.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/5255401319577312585'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/5255401319577312585'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/02/automate-config-changes-for-different.html' title='Automate config changes for different environments'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-365199805677729197</id><published>2008-01-03T08:30:00.000-06:00</published><updated>2008-01-06T12:50:25.871-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>A twisted, yet valid observation</title><content type='html'>Today, I again saw what is an all too frequent occurence in some dev shops - a failed build.  &lt;br /&gt;&lt;br /&gt;Rather, a grossly negligent failed build.  One that could have easily been avoided.  So to that developer, and others of similar ilk, I send this message:&lt;br /&gt;&lt;br /&gt;I know you only changed one line in a single file.  And I'm aware it takes ten minutes to build the solution on your machine.  I even realize that no one was going to pull down code at that precise moment.&lt;br /&gt;&lt;br /&gt;Nothing, however, pains the resident Build Guy more than that big red Build Failed icon.  Every time I see that, a little piece of me dies.&lt;br /&gt;&lt;br /&gt;And no, Fellow-Programmer-Who-Shall-Remain-Nameless, remembering to build immediately after checking in the file is not "close enough."  Sure you'll have the fix checked in even as the build reports the failure.  And sure, any other time of the day I would have been wandering the halls and never would have known.  But apologies won't help.  It's still too little, too late.  It's like applying the brakes &lt;b&gt;after&lt;/b&gt; running over the cat...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-365199805677729197?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/365199805677729197/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/01/twisted-yet-valid-observation.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/365199805677729197'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/365199805677729197'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/01/twisted-yet-valid-observation.html' title='A twisted, yet valid observation'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-3903818929737263341</id><published>2008-01-01T15:44:00.000-06:00</published><updated>2008-11-13T07:50:44.590-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>Customizing DataTips</title><content type='html'>A convenient debugging tool in Visual Studio is the ability to hover the mouse over an object and see the information currently stored there.  This is referred to as a DataTip.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_nWyC8gWd544/R3q0zCSNM6I/AAAAAAAAAGs/9XbhyGtlHsA/s1600-h/BaseClassDefault.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_nWyC8gWd544/R3q0zCSNM6I/AAAAAAAAAGs/9XbhyGtlHsA/s400/BaseClassDefault.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5150627912731145122" /&gt;&lt;/a&gt;&lt;br /&gt;If the class is derived from a base class, or contains other objects within, you can drill down to see those values as well.  Depending on the complexity of the object however, this can become tedious.  This is especially true if there are a couple values that you always want to see when debugging.&lt;br /&gt;&lt;br /&gt;To quickly see one or more properties on a class, you can do so using the DebuggerDisplay attribute in System.Diagnostics.  If I add the following to MyBaseClass, I can view the value of X without expanding the DataTip.  (The property to display is placed in braces.)&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;[DebuggerDisplay(&lt;span class="str"&gt;"The value of X is: {X}"&lt;/span&gt;)]&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_nWyC8gWd544/R3q1UiSNM7I/AAAAAAAAAG0/v57nCS78tuA/s1600-h/BaseClassCustom.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_nWyC8gWd544/R3q1UiSNM7I/AAAAAAAAAG0/v57nCS78tuA/s400/BaseClassCustom.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5150628488256762802" /&gt;&lt;/a&gt;&lt;br /&gt;If I derive a new class from MyBaseClass, I can set a DebuggerDisplay attribute that accesses values both from this class and the base.&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;[DebuggerDisplay(&lt;span class="str"&gt;"{X}, {Y}"&lt;/span&gt;)]&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; MyDerivedClass : MyBaseClass&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; _y;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Y&lt;br /&gt;    {&lt;br /&gt;        get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _y; }&lt;br /&gt;        set { _y = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_nWyC8gWd544/R3q1oiSNM8I/AAAAAAAAAG8/gatCvFadgD4/s1600-h/DerivedClassCustom.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_nWyC8gWd544/R3q1oiSNM8I/AAAAAAAAAG8/gatCvFadgD4/s400/DerivedClassCustom.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5150628831854146498" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-3903818929737263341?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/3903818929737263341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/01/customizing-datatips.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/3903818929737263341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/3903818929737263341'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2008/01/customizing-datatips.html' title='Customizing DataTips'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_nWyC8gWd544/R3q0zCSNM6I/AAAAAAAAAGs/9XbhyGtlHsA/s72-c/BaseClassDefault.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-4524315802450714598</id><published>2007-12-28T08:49:00.000-06:00</published><updated>2008-11-13T07:50:45.193-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VS2005'/><title type='text'>Treat Warnings as Errors</title><content type='html'>In a &lt;a href="http://automaticchainsaw.blogspot.com/2007/07/compiler-warnings-are-bad-thing.html"&gt;previous post&lt;/a&gt; I mentioned the importance of fixing compiler warnings.  I forgot about a useful project setting in Visual Studio that will cause all build warnings to display as errors instead.  From the project's properties page, select the Build tab.  Under "Treat warnings as errors," set the value to "All."  While this may be difficult to justify on existing projects with hundreds of warnings, this is something that should be set on all new projects.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_nWyC8gWd544/R3UNqySNM3I/AAAAAAAAAGU/TeM5yxUFbEI/s1600-h/BuildSettings.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_nWyC8gWd544/R3UNqySNM3I/AAAAAAAAAGU/TeM5yxUFbEI/s320/BuildSettings.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5149036777671832434" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_nWyC8gWd544/R3UNySSNM4I/AAAAAAAAAGc/uJzQcMrO3Kk/s1600-h/BuildWarnings.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_nWyC8gWd544/R3UNySSNM4I/AAAAAAAAAGc/uJzQcMrO3Kk/s400/BuildWarnings.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5149036906520851330" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_nWyC8gWd544/R3UN3ySNM5I/AAAAAAAAAGk/kBMatutW5Uk/s1600-h/BuildErrors.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_nWyC8gWd544/R3UN3ySNM5I/AAAAAAAAAGk/kBMatutW5Uk/s400/BuildErrors.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5149037001010131858" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-4524315802450714598?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/4524315802450714598/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/12/treat-warnings-as-errors.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/4524315802450714598'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/4524315802450714598'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/12/treat-warnings-as-errors.html' title='Treat Warnings as Errors'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_nWyC8gWd544/R3UNqySNM3I/AAAAAAAAAGU/TeM5yxUFbEI/s72-c/BuildSettings.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-8877744756004885371</id><published>2007-11-06T08:29:00.000-06:00</published><updated>2008-11-13T07:50:45.574-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>Quick and dirty debugging - DebugView and Trace.WriteLine</title><content type='html'>Here's another debug scenario for you.  After taking great effort in testing your application you hand it off to QA.  They throw it back with some interesting bug.  Using the exact same steps, you're unable to reproduce on your machine.  You have a general idea of where the app is failing, but can't be sure precisely what the issue is.&lt;br /&gt;&lt;br /&gt;At this point one usually resorts to some sort of logging.  These logging statements are placed in strategic locations through the suspect code (at every other line.)  If the bug is in the UI, the common method is MessageBox.Show.  If the problem is in an underlying assembly, you must resort to writing output to a text file.  The downside is that lots of message boxes wear you out, and it's always a pain tracking down the necessary code to write files.&lt;br /&gt;&lt;br /&gt;An easier option is to call Trace.WriteLine (located in System.Diagnostics.)  In my sample application (MyApp) I have a single button.  Inside the Click event, I add the following line&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; Trace.WriteLine("Button1 was clicked");&lt;/pre&gt;&lt;br /&gt;The event then calls a method in a separate library.  In this library method, I've added the following line ('x' was the parameter passed into the method)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; Trace.WriteLine("SomeMethod - Parameter x: " + x.ToString());&lt;/pre&gt;&lt;br /&gt;When I run the application from VisualStudio and click the button, the Output window contains the trace messages&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_nWyC8gWd544/RzB68Yy-KXI/AAAAAAAAAFs/B3D74vT3WZg/s1600-h/VsOutput.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_nWyC8gWd544/RzB68Yy-KXI/AAAAAAAAAFs/B3D74vT3WZg/s320/VsOutput.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5129735153441974642" /&gt;&lt;/a&gt;&lt;br /&gt;That's fine if you're running VS, but what about on a QA box?  For that I'm using &lt;a href="http://www.microsoft.com/technet/sysinternals/utilities/debugview.mspx"&gt;DebugView&lt;/a&gt;.  After starting up the utility, I fire up the sample application.  Click the button (which again calls Trace.Writeline) and DebugView displays the messages previously seen in Visual Studio.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_nWyC8gWd544/RzB7FYy-KYI/AAAAAAAAAF0/gR9orbchjro/s1600-h/DebugViewer.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_nWyC8gWd544/RzB7FYy-KYI/AAAAAAAAAF0/gR9orbchjro/s320/DebugViewer.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5129735308060797314" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-8877744756004885371?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/8877744756004885371/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/11/quick-and-dirty-debugging-debugview-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8877744756004885371'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8877744756004885371'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/11/quick-and-dirty-debugging-debugview-and.html' title='Quick and dirty debugging - DebugView and Trace.WriteLine'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_nWyC8gWd544/RzB68Yy-KXI/AAAAAAAAAFs/B3D74vT3WZg/s72-c/VsOutput.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-5999868155188462332</id><published>2007-11-06T08:23:00.000-06:00</published><updated>2008-11-13T07:50:45.938-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VS2005'/><title type='text'>Invalid Data Source crashes Visual Studio</title><content type='html'>Binding data object to a WinForms control is usually straightforward.  Say you have a ComboBox control.  Clicking the triangle on the top-right will display the ComboBox Tasks dialog.  &lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_nWyC8gWd544/RzB5GIy-KUI/AAAAAAAAAFU/vd9QMnuFmdM/s1600-h/EmptyDataSource.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_nWyC8gWd544/RzB5GIy-KUI/AAAAAAAAAFU/vd9QMnuFmdM/s320/EmptyDataSource.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5129733121922443586" /&gt;&lt;/a&gt;&lt;br /&gt;Once you check the box to "Use data bound items" you start by selecting the Data Source.  Normally, clicking the Data Source dropdown provides you with a list of existing items, as well as the option to create a new one.  A few days ago we ran into an issue where, instead of the datasources list, we were given this rather entertaining dialog&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_nWyC8gWd544/RzB5PIy-KVI/AAAAAAAAAFc/9MWZxkwH1UE/s1600-h/VsCrash.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_nWyC8gWd544/RzB5PIy-KVI/AAAAAAAAAFc/9MWZxkwH1UE/s320/VsCrash.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5129733276541266258" /&gt;&lt;/a&gt;&lt;br /&gt;With a few hints from the blogging community, we were directed to the Data Sources window (Data &gt; Show Data Sources, or Shift+Alt+D.)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_nWyC8gWd544/RzB5Xoy-KWI/AAAAAAAAAFk/HFa1bIDub4U/s1600-h/DataSourceWindow.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_nWyC8gWd544/RzB5Xoy-KWI/AAAAAAAAAFk/HFa1bIDub4U/s320/DataSourceWindow.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5129733422570154338" /&gt;&lt;/a&gt;&lt;br /&gt;Notice the first entry has an error icon.  This is due to a datasource pointing to a non-existent class.  Right-click the invalid entry and choose Remove Object.  Now the Data Source dropdown behaves as expected.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-5999868155188462332?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/5999868155188462332/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/11/invalid-data-source-crashes-visual.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/5999868155188462332'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/5999868155188462332'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/11/invalid-data-source-crashes-visual.html' title='Invalid Data Source crashes Visual Studio'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nWyC8gWd544/RzB5GIy-KUI/AAAAAAAAAFU/vd9QMnuFmdM/s72-c/EmptyDataSource.bmp' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-7148900807228939771</id><published>2007-11-01T11:02:00.000-05:00</published><updated>2008-11-13T07:50:46.474-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>Debugging with the Fusion logger</title><content type='html'>If you've spent much time developing, you've probably run into this scenario.  You're working along coding a new application.  Everything runs on your machine.  Then you hand it off to someone to test (that, or load it on the production server - let the users tell you what's wrong.)  Unfortunately, the app crashes as soon as you attempt to start it.  Looking in the Event Logs, you see generic .Net errors, but nothing that appears to help.  Short of installing VisualStudio on the box in question, how do you track down the issue?&lt;br /&gt;&lt;br /&gt;One place to start is the Fusion logs.  For this demo, I've created a class library (MyClassLib) and a command-line app (MyConsoleApp.)  The app makes a single method call into the library and then exits.  Nothing interesting to see when everything works.  If I delete MyClassLib.dll and run the application, I witness a rather unpleasant dialog&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_nWyC8gWd544/Ryn425KyE7I/AAAAAAAAAE0/23TL3HF2EqE/s1600-h/AppCrash.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_nWyC8gWd544/Ryn425KyE7I/AAAAAAAAAE0/23TL3HF2EqE/s320/AppCrash.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5127903272680690610" /&gt;&lt;/a&gt;&lt;br /&gt;When an app closes in a violent manner, the first place to look is the computer's event logs.  Unfortunately, the only entry for the app looks something like:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;"Faulting application myconsoleapp.exe, version 1.0.0.0, stamp 47293d14, faulting module kernel32.dll, version 5.1.2600.3119, stamp 46239bd5, debug? 0, fault address 0x00012a5b."&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;So now we turn to the Fusion logs.  The first step is to copy the Assembly Binding Log Viewer (fuslogvw.exe) from any machine with VS2005.  Start it up; it looks something like this:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_nWyC8gWd544/Ryn5FZKyE8I/AAAAAAAAAE8/ihi0gWFXOVY/s1600-h/EmptyLogger.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_nWyC8gWd544/Ryn5FZKyE8I/AAAAAAAAAE8/ihi0gWFXOVY/s320/EmptyLogger.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5127903521788793794" /&gt;&lt;/a&gt;&lt;br /&gt;Click on the Settings button.  In the dialog, select "Log bind failures to disk."  Check the box to "Enable custom log path" and specify an already-existing folder (the app won't create it for you.)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_nWyC8gWd544/Ryn5NZKyE9I/AAAAAAAAAFE/NqbQ7iFm85I/s1600-h/FusionLogSettings.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_nWyC8gWd544/Ryn5NZKyE9I/AAAAAAAAAFE/NqbQ7iFm85I/s320/FusionLogSettings.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5127903659227747282" /&gt;&lt;/a&gt;&lt;br /&gt;Note: According to official documentation, you should be able to use the default log directory.  In my experience, that never seemed to work.&lt;br /&gt;&lt;br /&gt;With the logger set up I again attempt to run the application.  Which again crashes.  Going back to the Fusion log viewer, click Refresh.  I now have a single entry&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_nWyC8gWd544/Ryn5VJKyE-I/AAAAAAAAAFM/9RsRGw0DJGI/s1600-h/OneFailedBind.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_nWyC8gWd544/Ryn5VJKyE-I/AAAAAAAAAFM/9RsRGw0DJGI/s320/OneFailedBind.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5127903792371733474" /&gt;&lt;/a&gt;&lt;br /&gt;Clicking on the entry loads the details in Internet Explorer (shown below.)  If you look halfway down the log, you'll see the reference to MyClassLib.  Near the end, you'll see the various locations it searched for the file.  Now it's a simple matter of finding a copy of my dll and placing in the search path.&lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;*** Assembly Binder Log Entry  (10/31/2007 @ 10:14:45 PM) ***&lt;br /&gt;&lt;br /&gt;The operation failed.&lt;br /&gt;Bind result: hr = 0x80070002. The system cannot find the file specified.&lt;br /&gt;&lt;br /&gt;Assembly manager loaded from:  C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll&lt;br /&gt;Running under executable  C:\temp\testcode\MyConsoleApp\bin\Release\MyConsoleApp.exe&lt;br /&gt;--- A detailed error log follows. &lt;br /&gt;&lt;br /&gt;=== Pre-bind state information ===&lt;br /&gt;LOG: User = SH\pgoins&lt;br /&gt;&lt;b&gt;LOG: DisplayName = MyClassLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null&lt;/b&gt;&lt;br /&gt; (Fully-specified)&lt;br /&gt;LOG: Appbase = file:///C:/temp/testcode/MyConsoleApp/bin/Release/&lt;br /&gt;LOG: Initial PrivatePath = NULL&lt;br /&gt;LOG: Dynamic Base = NULL&lt;br /&gt;LOG: Cache Base = NULL&lt;br /&gt;LOG: AppName = MyConsoleApp.exe&lt;br /&gt;Calling assembly : MyConsoleApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.&lt;br /&gt;===&lt;br /&gt;LOG: This bind starts in default load context.&lt;br /&gt;LOG: No application configuration file found.&lt;br /&gt;LOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config.&lt;br /&gt;LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).&lt;br /&gt;&lt;b&gt;LOG: Attempting download of new URL file:///C:/temp/testcode/MyConsoleApp/bin/Release/MyClassLib.DLL.&lt;br /&gt;LOG: Attempting download of new URL file:///C:/temp/testcode/MyConsoleApp/bin/Release/MyClassLib/MyClassLib.DLL.&lt;br /&gt;LOG: Attempting download of new URL file:///C:/temp/testcode/MyConsoleApp/bin/Release/MyClassLib.EXE.&lt;br /&gt;LOG: Attempting download of new URL file:///C:/temp/testcode/MyConsoleApp/bin/Release/MyClassLib/MyClassLib.EXE.&lt;/b&gt;&lt;br /&gt;LOG: All probing URLs attempted and failed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-7148900807228939771?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/7148900807228939771/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/11/debugging-with-fusion-logger.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7148900807228939771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7148900807228939771'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/11/debugging-with-fusion-logger.html' title='Debugging with the Fusion logger'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nWyC8gWd544/Ryn425KyE7I/AAAAAAAAAE0/23TL3HF2EqE/s72-c/AppCrash.bmp' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-7973723734972059995</id><published>2007-10-19T12:50:00.000-05:00</published><updated>2008-06-22T14:43:18.434-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Implicit conversions</title><content type='html'>I'm working on a project where request and response messages are serialized before sending across the wire.  We do this by calling an override of ToString().  So a line in the code might look like&lt;br /&gt;&lt;pre class="csharpcode"&gt;    response = myProvider.ProcessMessage(myMessage.ToString());&lt;/pre&gt;&lt;br /&gt;If I try to type&lt;br /&gt;&lt;pre class="csharpcode"&gt;    response = myProvider.ProcessMessage(myMessage);&lt;/pre&gt;&lt;br /&gt;I get a build error stating that it cannot implicitly convert type 'SomeCoolMessage' to 'string.'  So, what if I want to implicitly convert between the two?  In the SomeCoolMessage class I add a new operator&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;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;implicit&lt;/span&gt; &lt;span class="kwrd"&gt;operator&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt;(SomeCoolMessage m)&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; m.ToString();&lt;br /&gt;    }&lt;/pre&gt;&lt;br /&gt;Now I can write&lt;br /&gt;&lt;pre class="csharpcode"&gt;    response = myProvider.ProcessMessage(myMessage);&lt;/pre&gt;&lt;br /&gt;and everything just works.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-7973723734972059995?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/7973723734972059995/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/10/implicit-conversions.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7973723734972059995'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7973723734972059995'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/10/implicit-conversions.html' title='Implicit conversions'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-6867479828308764021</id><published>2007-10-05T16:43:00.000-05:00</published><updated>2007-11-01T11:07:58.459-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>Lessons learned</title><content type='html'>My current project is nearing completion of Phase 1.  Along the way, I've compiled a list of observations, lessons learned, etc, some of which I've already blogged.  Here are a few more:&lt;br /&gt;&lt;br /&gt;1)  When possible, use project references instead of file references.  It may seem convenient to break up the code into smaller solutions and use file references across solutions.  Problems arise when you have one master solution that builds all of the projects - you must explicitly set the build order.  With project references, VisualStudio determines the proper order for you, meaning less maintenance.  Also, when you right-click on a method/class/whatever and choose "Go To Definition," file references will take you to a page of metadata instead of the actual code.&lt;br /&gt;&lt;br /&gt;2)  Refactor often, and sooner rather than later.  Say you're working on set of classes that use a common interface.  You then decide to build a base class from that interface, and derive the other classes from the base.  Don't leave old classes as-is and use the base only for new classes.  One issue is you potentially leave bugs that the base was specifically designed to address.  Another is that when a new team member joins the project, he will likely use existing code as a template for adding new functionality.  If he sees the non-base-derived class and builds his own directly from the interface, refactoring later becomes more difficult.&lt;br /&gt;&lt;br /&gt;3)  Remove dead code.  When you replace one method with another, delete the old method.  When functionality is no longer required, delete that functionality.  Don't leave it in.  Don't comment it out.  If you need that code later, pull it from your source repository.  As the source grows in size, you'll have enough to deal with without adding the extra hassle associated with dead code.&lt;br /&gt;&lt;br /&gt;4)  Obsolete code if you can't currently delete it.  Say you replace a method with another, but you can't replace all of the method calls at the moment (this especially happens with public methods.)  Mark the method as obsolete and note the proper method to use instead.  In C# this looks like &lt;i&gt;[Obsolete("Use method foo instead")]&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;5)  When changing the database schema, change the data access code at the same time.  Until these two are in sync, your code doesn't work.  You should have failing unit tests to flag the issues, but that's not always the case.  In that instance, your first indication that there is a mismatch is when a developer attempts to run code that he thought was working.  Often, the developer attempts to track down the problem, which another dev already knew about.  All of which leads to wasted time.&lt;br /&gt;&lt;br /&gt;6)  Reduce confusion within the code.  Maybe there's a method being incorrectly called, or called when another should have been used instead.  It's not enough to correct the developer.  Look at why the error occurred.  Perhaps better comments on the method would help (use xml comments to populate intellisense.)  Or perhaps the method could be named better.  The problem may also be due to poorly architected code in need of refactoring.  Bottom line: fix the issue instead of addressing symptoms.&lt;br /&gt;&lt;br /&gt;7)  If you can't unit test the entire codebase, write tests for the error-prone code.  Ideally you want 100% code coverage from your unit tests.  In reality this isn't going to happen.  Therefore, focus unit tests on problematic and/or complex areas of code.  We have lots of code binding to dataset columns.  These columns are taken directly from the database.  If a column was dropped from the table, you won't receive a compiler error on &lt;i&gt;row["DroppedColumn"]&lt;/i&gt; but you will receive a runtime exception.  These issues need to be caught by the unit tests, not the QA team.&lt;br /&gt;&lt;br /&gt;8)  Code generation must be handled &lt;b&gt;very&lt;/b&gt; carefully.  Most see code generation as an easy way to save time on a project.  This is especially true for database access code - basic CRUD operations don't change from one table to the next.  Once you have the first generation complete, how you proceed becomes critical.  Say you spend a few weeks writing code that uses the autogen code.  Someone then decides to make changes to the templates and regen everything.  While the intent may have been valid, this regen quite likely broke existing code.  At a minimum, your unit tests fail and you can easily find and fix all of the problems.  But even then, time must be spent on the fix.  If you don't have a decent set of unit tests - be prepared for the increase in tickets from QA.  Unless your autogen code is truly separate from the rest of the project, it's probably better in the long run to gen once and modify by hand after that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-6867479828308764021?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/6867479828308764021/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/10/lessons-learned.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/6867479828308764021'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/6867479828308764021'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/10/lessons-learned.html' title='Lessons learned'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-2960259832323843527</id><published>2007-09-24T09:10:00.000-05:00</published><updated>2007-11-01T11:08:38.096-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Hidden Desktops and NUnitForms</title><content type='html'>In my &lt;a href="http://automaticchainsaw.blogspot.com/2007/09/winforms-testing-using-nunitforms.html"&gt;last post&lt;/a&gt; I noted a problem working with NUnitForms.  I was unable to get the hidden desktop to work with a [SetUp] method.  After digging through the source code, I have my solution.&lt;br /&gt;&lt;br /&gt;The code that sets up the hidden desktop is in the method init().  This method is marked with the [SetUp] attribute.  When I created my own method with this attribute, init() was no longer being called.  Thus, no hidden desktop.&lt;br /&gt;&lt;br /&gt;The solution is to override the Setup() method provided in NUnitFormsTest, but to &lt;b&gt;not&lt;/b&gt; mark it with the [SetUp] attribute.  The last thing init() does before exiting is make a call to Setup().  The TearDown attribute and method have a similar implementation.  &lt;br /&gt;&lt;br /&gt;When the documentation seems to be lacking, it's always nice to have the source code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-2960259832323843527?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/2960259832323843527/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/09/hidden-desktops-and-nunitforms.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2960259832323843527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2960259832323843527'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/09/hidden-desktops-and-nunitforms.html' title='Hidden Desktops and NUnitForms'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-5213393798479173320</id><published>2007-09-21T10:25:00.000-05:00</published><updated>2008-06-22T14:43:08.044-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>WinForms testing using NUnitForms</title><content type='html'>I've been spending a lot of time lately coding screens for a WinForms application.  Although I've written unit tests for the server components, the client side is somewhat lacking.  Each time I change a screen I have to manually test those changes and verify I didn't break anything.  In an attempt at automating the process, I've started looking at &lt;a href="http://nunitforms.sourceforge.net/"&gt;NUnitForms&lt;/a&gt;, an extension to NUnit.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Setup&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;1)  Install NUnitForms&lt;br /&gt;2)  Create a project for your NUnit tests.  Configure NUnit as normal.&lt;br /&gt;3)  Add references to your application project, NUnitForms, System.Windows.Forms, and any third-party controls you use on your application's forms.  &lt;br /&gt;4)  In the test fixtures, add 'using NUnit.Extensions.Forms'&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Basic forms testing&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Let's say my application under test (AUT) contains a form, Form1.  The first step is to create and display an instance of that form&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    Form1 testForm = &lt;span class="kwrd"&gt;new&lt;/span&gt; Form1();&lt;br /&gt;    testForm.Show();&lt;/pre&gt;&lt;br /&gt;Say the form has a button - btnOne.  Pressing the button programatically looks like this&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    ButtonTester btnOneTester = &lt;span class="kwrd"&gt;new&lt;/span&gt; ButtonTester(&lt;span class="str"&gt;"btnOne"&lt;/span&gt;);&lt;br /&gt;    btnOneTester.Click();&lt;/pre&gt;&lt;br /&gt;Upon clicking this button, a label was updated with the everyone's favorite power tool.  To verify&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    LabelTester labelOneTester = &lt;span class="kwrd"&gt;new&lt;/span&gt; LabelTester(&lt;span class="str"&gt;"labelOne"&lt;/span&gt;);&lt;br /&gt;    Assert.AreEqual(&lt;span class="str"&gt;"Chainsaw"&lt;/span&gt;, labelOneTester.Text, &lt;span class="str"&gt;"Label text doesn't match expected"&lt;/span&gt;);&lt;/pre&gt;&lt;br /&gt;Though it's not required, it's probably a good idea to close the form instead of letting it fall out of scope&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    testForm.Close();&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Using the hidden desktop&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Running these tests on your local machine doesn't pose any issues.  If you run them on a build server, however, you'll likely find that they fail - there's no window for the forms to be displayed in.  Fortunately, you can send them to a hidden desktop.&lt;br /&gt;&lt;br /&gt;To do so, your test fixture must inherit from NUnitFormTest.  Then, add the following property to the class&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; UseHidden&lt;br /&gt;    {&lt;br /&gt;        get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;; }&lt;br /&gt;    }&lt;/pre&gt;&lt;br /&gt;One warning - In most of my test fixtures, I tend to put common code in a [Setup] method.  I'm finding that when I have this defined, forms are not being sent to the hidden desktop.  I've not spent much time on it, so I'm not sure if it's something I'm doing wrong, or if it's a bug in the tool.  I'll post more info if/when I figure it out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-5213393798479173320?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/5213393798479173320/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/09/winforms-testing-using-nunitforms.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/5213393798479173320'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/5213393798479173320'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/09/winforms-testing-using-nunitforms.html' title='WinForms testing using NUnitForms'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-1297770405040915561</id><published>2007-09-16T16:12:00.000-05:00</published><updated>2007-11-06T08:28:20.320-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>Silverlight preparation</title><content type='html'>A &lt;a href="http://zduck.blogspot.com/"&gt;friend&lt;/a&gt; recently decided to start a monthly Hack Day for a small group of colleagues.  Given that it's often difficult to motivate oneself to study new technology, the idea is to gather like-minded slackers and force each other to do a little research.&lt;br /&gt;&lt;br /&gt;After some discussion, we decided on &lt;a href="http://silverlight.net/GetStarted/"&gt;Silverlight&lt;/a&gt; as the first topic.  Here's what I did in preparation:&lt;br /&gt;&lt;br /&gt;1)  Downloaded a &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=3B72271C-E996-4989-898D-72D684966CE6&amp;displaylang=en"&gt;VPC image of Orcas&lt;/a&gt; (aka VS2008.)  You have to download a base image along with the Orcas image - nearly 14GB total.&lt;br /&gt;&lt;br /&gt;2)  Installed various 1.0 and 1.1 packages:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/silverlight/downloads.aspx#4_0"&gt;Silverlight 1.0 Runtime&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=FB7900DB-4380-4B0F-BB95-0BAEC714EE17&amp;displaylang=en"&gt;Silverlight 1.0 SDK&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/silverlight/license-win-dev.aspx"&gt;Silverlight 1.1 Alpha Refresh&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=B52AEB39-1F10-49A6-85FC-A0A19CAC99AF&amp;displaylang=en"&gt;Silverlight Tools for VS2008&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=69540337-B619-4A47-AC27-52D8AF3A7830&amp;displaylang=en"&gt;Expression Blend 2 August Preview&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;3)  Watched the &lt;a href="http://silverlight.net/GetStarted/"&gt;Getting Started&lt;/a&gt; video and a few &lt;a href="http://www.microsoft.com/expression/kc/resources.aspx?product=blend&amp;type=tutorial"&gt;Blend tutorials&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-1297770405040915561?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/1297770405040915561/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/09/silverlight-preparation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1297770405040915561'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1297770405040915561'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/09/silverlight-preparation.html' title='Silverlight preparation'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-6801291858170384361</id><published>2007-09-16T14:22:00.000-05:00</published><updated>2007-11-01T11:07:58.459-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='misc'/><title type='text'>Uncompressed images and file sizes</title><content type='html'>Scanning paper documents can be a useful way to transfer and store data.  This of course assumes you are scanning bitonal, with some form of image compression.  If you were to scan in 24-bit color with no compression, you'd find the output less than useful.&lt;br /&gt;&lt;br /&gt;To see this, let's start with a 1 inch square, at 10 dots per inch (dpi.)  The total number of dots (pixels) is 10x10, or 100.  If we create a larger square, say 5 inches on each side, we now have 25 square inches.  At 10dpi, that's 2500 pixels (100 dots per square x 25 squares.)  If we scanned a normal sheet of paper (8.5x11) we have a total of 93500 pixels.&lt;br /&gt;&lt;br /&gt;Going back to the 1 inch square, say we double the dpi to 20.  What does that do to the pixel count?  You might initially say it doubles.  If you calculate it, however, you find that you quadrupled the number (20x20 = 400.)&lt;br /&gt;&lt;br /&gt;The total number of pixels can be found using the formula:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (horizontal dpi * image width in inches) * (vertical dpi * image height in inches) = total pixels&lt;/pre&gt;&lt;br /&gt;A normal sheet of paper, scanned at 100dpi&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (100 * 8.5) * (100 * 11) = 935,000 pixels&lt;/pre&gt;&lt;br /&gt;The other item to consider is the bit depth of the image.  For a bitonal image, each pixel is represented by 1 bit (black or white.)  Color images, such as photos, are saved with RGB values for each pixel.  This typically requires one byte per color, or three bytes per pixel&lt;br /&gt;&lt;br /&gt;To calculate the total number of bytes per image:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; total pixels * bytes per pixel = total bytes&lt;/pre&gt;&lt;br /&gt;A normal sheet of paper, again at 100dpi, scanned in 1 bit-per-pixel (bpp)&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; 935000 * 0.125 = 116,875 bytes&lt;/pre&gt;&lt;br /&gt;That same page, scanned in 24bpp&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; 935000 * 3 = 2,805,000 bytes (~2.5MB)&lt;/pre&gt;&lt;br /&gt;As you can see, scanning in full color without compression creates much larger images.  Again with 24bit color, here are some common scanner dpi's with their resulting image sizes (in bytes.)&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; 200 dpi = (200 * 8.5) * (200 * 11) * 3 = 11,220,000&lt;br /&gt;&lt;br /&gt; 300 dpi = (300 * 8.5) * (300 * 11) * 3 = 25,245,000&lt;br /&gt;&lt;br /&gt; 600 dpi = (600 * 8.5) * (600 * 11) * 3 = 100,980,000&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-6801291858170384361?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/6801291858170384361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/09/uncompressed-images-and-file-sizes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/6801291858170384361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/6801291858170384361'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/09/uncompressed-images-and-file-sizes.html' title='Uncompressed images and file sizes'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-1115799263040444894</id><published>2007-09-04T14:49:00.000-05:00</published><updated>2010-08-09T16:05:37.792-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='NUnit'/><title type='text'>Upgrading from NUnit 2.2 to 2.4</title><content type='html'>Until recently, I was running &lt;a href="http://www.nunit.org/"&gt;NUnit&lt;/a&gt; 2.2.9 on both my work and home computers.  This weekend I decided to upgrade my home computer to version 2.4.3.  The quick and painless process went as follows:&lt;br /&gt;&lt;br /&gt;1)  Uninstall v2.2.9&lt;br /&gt;2)  Install v2.4.3&lt;br /&gt;3)  Open an existing project containing unit tests&lt;br /&gt;4)  Updating the references to point to the new assemblies&lt;br /&gt;5)  Compile and run...&lt;br /&gt;&lt;br /&gt;Well, it all worked except for that last step.  At one point, I seem to recall NUnit requiring you to reference nunit.core.  Whatever that reason, it's no longer a requirement, and was the cause of the build failure.  After removing the reference, everything ran as before.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Constraint-based assertions&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;One of the most noticeable changes in version 2.4 was the inclusion of constraint-based assertions, similar to some of the mock frameworks available.  Previously, you might write assertions like:&lt;br /&gt;&lt;br /&gt;Assert.IsTrue(age &lt; 21);&lt;br /&gt;Assert.AreEqual(9, age);&lt;br /&gt;&lt;br /&gt;Using constraints, you can now write:&lt;br /&gt;&lt;br /&gt;Assert.That(age, Is.LessThan(21));&lt;br /&gt;Assert.That(age, Is.EqualTo(9));&lt;br /&gt;&lt;br /&gt;Also, if your test fixture is derived from AssertionHelper, you can shorten the previous lines to:&lt;br /&gt;&lt;br /&gt;Expect(age, LessThan(21));&lt;br /&gt;Expect(age, EqualTo(9));&lt;br /&gt;&lt;br /&gt;Note: you will need to add &lt;i&gt;using&lt;/i&gt; statements for NUnit.Framework.Constraints and NUnit.Framework.SyntaxHelpers.  For more examples, including comparisons to the older Assert methods, look for AssertSyntaxTests.cs under the NUnit install directory.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-1115799263040444894?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/1115799263040444894/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/09/upgrading-from-nunit-22-to-24.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1115799263040444894'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1115799263040444894'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/09/upgrading-from-nunit-22-to-24.html' title='Upgrading from NUnit 2.2 to 2.4'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-2400236354111828347</id><published>2007-08-16T09:19:00.000-05:00</published><updated>2008-11-13T07:50:46.807-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VS2005'/><title type='text'>Custom Code Snippets</title><content type='html'>I'm not exactly sure when snippets were added to VisualStudio.  I'm also not sure why I neglected them this long.  I guess I just wasn't one of the Cool Kids.  Hopefully I can make amends.&lt;br /&gt;&lt;br /&gt;In case you are unfamiliar with snippets, this is the feature that lets you type 'prop' inside a class definition, press 'Tab' twice, and end up with a complete property definition.  Even better, it highlights the items to modify, and you can easily Tab between them as you edit.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_nWyC8gWd544/RsRdKaVJH2I/AAAAAAAAAEA/kJwbUXmccHI/s1600-h/prop_expanded.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_nWyC8gWd544/RsRdKaVJH2I/AAAAAAAAAEA/kJwbUXmccHI/s400/prop_expanded.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5099303111538319202" /&gt;&lt;/a&gt;&lt;br /&gt;This is cool.  Knowing this is there and using the built-in snippets, however, doesn't make one cool.  True coolness occurs when one creates one's own.  My journey began with an existing .snippet file.  The path to these can be found in the Code Snippet Manager (under the Tools menu.)  A few changes and I had the following:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;="1.0"&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt;&lt;span class="kwrd"&gt;="utf-8"&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;CodeSnippets&lt;/span&gt;  &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"&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;CodeSnippet&lt;/span&gt; &lt;span class="attr"&gt;Format&lt;/span&gt;&lt;span class="kwrd"&gt;="1.0.0"&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;Header&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;Title&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;test&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Title&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;Shortcut&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;test&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Shortcut&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;Description&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Code snippet for NUnit test&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Description&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;Author&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Pedro&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Author&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;SnippetTypes&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;SnippetType&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Expansion&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;SnippetType&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;SnippetTypes&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;Header&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;Snippet&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;Declarations&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;Literal&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;ID&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;testName&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ID&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;ToolTip&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Test name&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ToolTip&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;Default&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;myUnitTest&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Default&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;Literal&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;Declarations&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;Code&lt;/span&gt; &lt;span class="attr"&gt;Language&lt;/span&gt;&lt;span class="kwrd"&gt;="csharp"&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;[CDATA[[Test]&lt;br /&gt;    public void $testName$()&lt;br /&gt;    {            &lt;br /&gt;        Assert.Fail("TODO: Implement test");$end$&lt;br /&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;Code&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;Snippet&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;CodeSnippet&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;CodeSnippets&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For those following along at home, save the above as a .snippet file.  This can either be placed with the existing snippets, or in the "My Code Snippets" folder buried under "My Documents."  Once saved, the Snippet Manager should list the new file.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_nWyC8gWd544/RsRdjaVJH3I/AAAAAAAAAEI/A9kZ1FRdVDM/s1600-h/CodeSnippetManager.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_nWyC8gWd544/RsRdjaVJH3I/AAAAAAAAAEI/A9kZ1FRdVDM/s320/CodeSnippetManager.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5099303541035048818" /&gt;&lt;/a&gt;&lt;br /&gt;To try it out, open up a .cs file containing unit tests.  In a blank area between existing tests, type 'test' and press 'Tab' twice.  Assuming I didn't screw up the above xml, you should now have the start of a new unit test.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_nWyC8gWd544/RsRdqaVJH4I/AAAAAAAAAEQ/tbhxdzlBi9E/s1600-h/prop_test_expanded.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_nWyC8gWd544/RsRdqaVJH4I/AAAAAAAAAEQ/tbhxdzlBi9E/s400/prop_test_expanded.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5099303661294133122" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-2400236354111828347?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/2400236354111828347/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/08/custom-code-snippets.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2400236354111828347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2400236354111828347'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/08/custom-code-snippets.html' title='Custom Code Snippets'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nWyC8gWd544/RsRdKaVJH2I/AAAAAAAAAEA/kJwbUXmccHI/s72-c/prop_expanded.bmp' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-6589827746173954619</id><published>2007-07-25T12:39:00.000-05:00</published><updated>2007-07-25T12:41:24.628-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Compiler warnings are a Bad Thing</title><content type='html'>Most projects I've worked on contained a sizeable number of compiler warnings.  These are usually ignored by developers as being unimportant.  So there are a few (dozen) variables defined that are never used - so what?  Duplicate 'using' statements - that can't hurt anything...&lt;br /&gt;&lt;br /&gt;It's true that some warnings are mostly harmless.  The problem is that these warnings often hide other, more important ones.  A few serious ones that come to mind:&lt;br /&gt;&lt;br /&gt;- Unreachable code.  Perhaps there's a return statement halfway through a function.  Or a conditional that will always evaluate true (or false.)  These often have unintended side effects.&lt;br /&gt;&lt;br /&gt;- A variable is never assigned to, and will always have a default value.  You've created a variable, foo, that you're using in your code, perhaps in a method call or conditional.  The problem is, you never set foo to anything.  It's possible the variable should be removed or replaced with a constant.  But it's also possible you forgot to retrieve or calculate something.&lt;br /&gt;&lt;br /&gt;- A class member hides an inherited member.  Maybe you intended to replace it with your own.  In that case, use 'new' to explicitly document the desired effect.  If hiding was unintentional, you're better off renaming the member.  Otherwise, you may later decide you need that hidden item.  At which point you end up with a bit of code rework.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-6589827746173954619?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/6589827746173954619/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/07/compiler-warnings-are-bad-thing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/6589827746173954619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/6589827746173954619'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/07/compiler-warnings-are-bad-thing.html' title='Compiler warnings are a Bad Thing'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-7623640584175700924</id><published>2007-07-24T08:35:00.000-05:00</published><updated>2007-07-24T08:37:46.075-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>Single responsibility builds</title><content type='html'>When I joined my current project, the CI build server (CC.Net) was already in place.  For the most part, things were in working order.  One item I took exception to was the fact that every build copied files to the development server.  The idea being that a developer can run tests to verify that all of the pieces are working correctly.  For most of the team, however, this is instead used as a convenient way to code the UI without running the services locally.  This makes sense.&lt;br /&gt;&lt;br /&gt;The problem, however, comes in when a significant change is made to that code (as in the recent data access changes.)  Much of the code still has bugs to work out, despite the fact that the code compiles.  The way the build is set up, the copies to the server happen after the compile, regardless of the unit test results.  The end result is that after the change, developers could no longer test against the server's build.&lt;br /&gt;&lt;br /&gt;Ideally, the continuous build process would not touch the dev server files.  Instead, a separate build is created to copy the files on demand (using a Force Build in CC.Net.)  When the build is in a faulty state, UI developers can continue working off a known-good base, while others can iron out the bugs in the server code.  Another option would be to fail the build if any unit tests fail, so the file copies aren't carried out.  Of course, this assumes the tests normally pass.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-7623640584175700924?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/7623640584175700924/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/07/single-responsibility-builds.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7623640584175700924'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/7623640584175700924'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/07/single-responsibility-builds.html' title='Single responsibility builds'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-2720946035179390644</id><published>2007-07-23T17:22:00.001-05:00</published><updated>2007-07-24T08:35:36.648-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Always address failing unit tests</title><content type='html'>I cannot &lt;a href="http://automaticchainsaw.blogspot.com/2007/06/notes-on-unit-testing.html"&gt;stress enough&lt;/a&gt; the value of unit tests.  Whether adding new features or refactoring existing code, you want some validation that you haven't broken existing functionality.  Unit tests are usually the fastest way to accomplish this.&lt;br /&gt;&lt;br /&gt;This is why it annoys me when unit tests are left in a failing state.  In some cases, the tests are invalid and need to be removed.  In other cases, they need to be updated to match code changes.  Regardless of why a test now fails, it needs to be corrected.&lt;br /&gt;&lt;br /&gt;On a project I'm currently involved in, there was a significant rework of data access code.  As you can imagine, this introduced a number of bugs, many of which were caught by now-failing unit tests.  This is a good thing - that's what the unit tests are for.  The problem is that the 50 newly-failing unit tests are mixed in with the 40 already-failing unit tests.  We need the new failures fixed quickly, but sorting these from the "junk" unit tests will take time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-2720946035179390644?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/2720946035179390644/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/07/always-address-failing-unit-tests.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2720946035179390644'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2720946035179390644'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/07/always-address-failing-unit-tests.html' title='Always address failing unit tests'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-9161088042934088742</id><published>2007-07-17T14:39:00.000-05:00</published><updated>2008-11-13T07:50:47.143-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VS2005'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>Debugging with Exception Breakpoints</title><content type='html'>How many times has this happened to you?  You're working on code that's not quite functioning correctly.  You suspect there's an exception being thrown somewhere, but it's being caught and ignored.  Maybe this was intentional, or maybe it was poorly written code.  Either way, you need to locate the problem.  Visual Studio 2005 has a handy little tool to help - Exception Breakpoints.&lt;br /&gt;&lt;br /&gt;Say you have code that looks like this:&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;int&lt;/span&gt; a = 2;&lt;br /&gt;        &lt;span class="kwrd"&gt;int&lt;/span&gt; b = 0;&lt;br /&gt;        &lt;span class="kwrd"&gt;int&lt;/span&gt; c = a / b;  &lt;span class="rem"&gt;// does not compute&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="kwrd"&gt;catch&lt;/span&gt;&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="rem"&gt;// Do nothing&lt;/span&gt;&lt;br /&gt;    }&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you were to run this code, you'd never know that there was a problem (well, not until you tried to use the value of 'c' elsewhere.)  What we want to do is have the debugger break as soon as an exception is thrown.  To do this, open the Exceptions dialog, either through the menu (Debug &amp;gt; Exceptions) or the keyboard shortcut (Ctrl+D followed by E).&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_nWyC8gWd544/Rp0bd71LtTI/AAAAAAAAADw/goHbpYJs6nY/s1600-h/Exceptions+window.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_nWyC8gWd544/Rp0bd71LtTI/AAAAAAAAADw/goHbpYJs6nY/s400/Exceptions+window.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5088253355089442098" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Under the Thrown column, check the box next to the Common Language Runtime Exceptions.  Now, when an exception is thrown, VS immediately breaks at the offending line of code.  One word of warning - Depending on the size of the code, you may find far more exceptions being thrown than you had expected.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_nWyC8gWd544/Rp0bnL1LtUI/AAAAAAAAAD4/GCiVZVnHsHk/s1600-h/Exception+Breakpoint.bmp"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_nWyC8gWd544/Rp0bnL1LtUI/AAAAAAAAAD4/GCiVZVnHsHk/s400/Exception+Breakpoint.bmp" border="0" alt=""id="BLOGGER_PHOTO_ID_5088253514003232066" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-9161088042934088742?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/9161088042934088742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/07/debugging-with-exception-breakpoints.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/9161088042934088742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/9161088042934088742'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/07/debugging-with-exception-breakpoints.html' title='Debugging with Exception Breakpoints'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_nWyC8gWd544/Rp0bd71LtTI/AAAAAAAAADw/goHbpYJs6nY/s72-c/Exceptions+window.bmp' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-894737788597965364</id><published>2007-06-29T08:25:00.000-05:00</published><updated>2007-06-29T08:30:11.482-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='coding'/><title type='text'>Notes On Unit Testing</title><content type='html'>Lately, I seem to be spending a lot of time writing and updating unit tests.  Along the way, I've made a number of observations.  The syntax I'm using is taken from &lt;a href="http://www.nunit.org/"&gt;NUnit&lt;/a&gt;, but the ideas apply to any unit test framework.&lt;br /&gt;&lt;br /&gt;1) If you choose to Ignore a unit test, note why it's being ignored and optionally how it is to be addressed.  In NUnit, the attribute looks like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; [Ignore("We can't run this test until the hardware is in place")]&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Not only is it easier for a dev to figure out later, but it will show up in the build report, making it easy to see the reason without opening up the code.&lt;br /&gt;&lt;br /&gt;2) Similarly, use comments in all Assert statements noting the reason for the failure.  Again the NUnit syntax&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; Assert.AreEqual(expectedAge, actualAge, "Actual age doesn't match expected");&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Without this, the NUnit report tells you that 12 didn't match 45, but it doesn't tell you whether you were comparing age or IQ.&lt;br /&gt;&lt;br /&gt;3) Never copy/paste code.  We all follow this rule in production code, but it is often ignored when writing unit tests.  If every test requires a login before doing anything useful, move the login code to a separate method and mark it with a SetUp attribute.  If some tests need to fail login, leave off the Setup attribute, but call the method from those unit tests that need it.  Note also that you can use Asserts in these methods, so you can still verify proper execution within the methods.&lt;br /&gt;&lt;br /&gt;4) Use constants whenever appropriate.  If every unit test accesses the same server, move the server name to a string constant.  This way, when you later shift to a new test box, you only replace one string.&lt;br /&gt;&lt;br /&gt;5) Use a TearDown method to clean up after a test.  Largely, this is to reduce the copy/paste of code (see item #3.)  This also has to do with not using "try/finally" blocks.  It is true that a failed Assert statement is simply throwing an exception.  And technically, you could do code cleanup inside a finally block.  But this isn't a clean solution (which is why the TearDown attribute exists.)  One note: you may have to do some checking within the method.  You wouldn't want to dispose a null object.&lt;br /&gt;&lt;br /&gt;6) Never hard-code expected values from a database.  I've seen numerous unit tests similar to:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; Assert.AreEqual(14, user.ID);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Primary keys are particularly problematic, but any field could cause issues, especially if users (or other unit tests) update values in the table.&lt;br /&gt;&lt;br /&gt;One approach is to pull data using some other means.  Perhaps by using inline SQL.  Perhaps there's another stored proc or service that returns the same info.  Either method means the tests don't need to be updated simply because the data changes.&lt;br /&gt;&lt;br /&gt;A second approach is to use mock objects and avoid real data altogether.  Assuming you've coded to an interface, you can use a tool like &lt;a href="http://nmock.org/"&gt;NMock&lt;/a&gt; or &lt;a href="http://www.ayende.com/projects/rhino-mocks.aspx"&gt;Rhino.Mocks&lt;/a&gt; to simulate data retrieval.&lt;br /&gt;&lt;br /&gt;7) Test for exception cases using the ExpectedException attribute.  There's no need to write a try/catch block, just to verify that a particular exception was thrown.  ExpectedException can handle that for you, saving time writing code.  One argument against it is that you can only test one exception case per test.  You could instead have multiple try/catch tests within a single unit test.  The problem here is that NUnit logs one error per test.  If you have multiple errors, only one will be logged.  You won't notice the other issues until the first has been addressed.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;And Most Importantly:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;8) Fix broken unit tests (Keep the unit tests current.)  I've seen instances where unit tests were written to verify current behavior, but were then ignored as the code was modified.  A large portion of a unit test's value comes from its ability to monitor code, flagging errors as soon as they are introduced.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-894737788597965364?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/894737788597965364/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/06/notes-on-unit-testing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/894737788597965364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/894737788597965364'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/06/notes-on-unit-testing.html' title='Notes On Unit Testing'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-3674040763773069616</id><published>2007-06-21T12:27:00.000-05:00</published><updated>2007-06-29T08:29:38.011-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Stopping a COM+ Application Via the Command Line</title><content type='html'>I'm currently working on a project requiring multiple steps to deploy correctly.  Being the efficient (aka lazy) developer that I am, I decided to automate some of the process.  One step calls for stopping a COM+ application.  I'm assuming there's a command line utility to handle this, but I've not yet found it.  I tried consulting a friendly &lt;a href="http://zduck.blogspot.com"&gt;guru&lt;/a&gt;, but that didn't help.  So, I was forced to write the VBScript below.&lt;br /&gt;&lt;br /&gt;To use, create a new file, StopComApp.vbs, and add the following:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; dim objCatalog&lt;br /&gt; set objCatalog = CreateObject("COMAdmin.COMAdminCatalog")&lt;br /&gt;&lt;br /&gt; set args = WScript.Arguments&lt;br /&gt; serviceName = args.Item(0)&lt;br /&gt;&lt;br /&gt; objCatalog.ShutDownApplication serviceName&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To use, run the following from the command prompt (or batch file):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt; wscript StopComApp.vbs &amp;lt;AppName&amp;gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-3674040763773069616?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/3674040763773069616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/06/stopping-com-application-via-command.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/3674040763773069616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/3674040763773069616'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/06/stopping-com-application-via-command.html' title='Stopping a COM+ Application Via the Command Line'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-2539812011736197005</id><published>2007-06-10T13:30:00.000-05:00</published><updated>2007-06-29T08:28:35.531-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>A Useful Way To Launch WinDiff</title><content type='html'>A co-worker recently expressed his annoyance that certain tools installed with Visual Studio didn't have Start menu shortcuts.  One in particular was WinDiff.  In my experience, however, starting WinDiff by itself was never very useful.  Once it was running you still had to browse to the files (or folders) you wanted to compare.  I prefer selecting two items, right-clicking, and choosing WinDiff from the menu.&lt;br /&gt;&lt;br /&gt;To set this up, create a new file, windiff.bat, with the following:&lt;br /&gt;&lt;pre&gt; "C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\Bin\WinDiff.exe" %1 %2&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Save the file to C:\Documents and Settings\&amp;lt;username&amp;gt;\SendTo&lt;br /&gt;&lt;br /&gt;To use, select two files in the same folder.  Right-click and choose Send To &amp;gt; windiff.bat.  This can also be used to diff the contents of two folders.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-2539812011736197005?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/2539812011736197005/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/06/useful-way-to-launch-windiff.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2539812011736197005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/2539812011736197005'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/06/useful-way-to-launch-windiff.html' title='A Useful Way To Launch WinDiff'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-1994601683679878098</id><published>2007-06-04T13:22:00.000-05:00</published><updated>2008-11-13T07:50:47.918-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SourceSafe'/><title type='text'>Pseudo-changesets In SourceSafe</title><content type='html'>Let's say you make a code change that spans multiple files across several projects.  When the change is complete, you need to check in all of the files at the same time.  Otherwise, you end up with a broken build.  Most source-control systems include the concept of a changeset.  As you check out files, they are grouped in a specified set.  After the modifications have been made and tested, you check in the changeset as opposed to the individual files.  The bad news: SourceSafe doesn't include changesets.  The good news: you can work around the limitation.&lt;br /&gt;&lt;br /&gt;I previously added the MSBuild.Community.Tasks code to SourceSafe.  Let's say I modified code within the XmlQuery task.  This also required changing the unit tests.  To see all of the relevant checkouts, select the folder common to both projects ('Source' in this case.)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_nWyC8gWd544/RmRYt0qlrZI/AAAAAAAAADQ/YR1ch2OVxQY/s1600-h/SelectProject.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_nWyC8gWd544/RmRYt0qlrZI/AAAAAAAAADQ/YR1ch2OVxQY/s400/SelectProject.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5072276624580652434" /&gt;&lt;/a&gt;&lt;br /&gt;From the menu, choose View &amp;gt; Search &amp;gt; Status Search.  In the "Search for Status" dialog, select the options to display files checked out to you, in current project and all subprojects.  Click OK.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_nWyC8gWd544/RmRZjkqlrcI/AAAAAAAAADo/d8GeAJ5kQC0/s1600-h/SearchSettings.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_nWyC8gWd544/RmRZjkqlrcI/AAAAAAAAADo/d8GeAJ5kQC0/s320/SearchSettings.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5072277547998621122" /&gt;&lt;/a&gt;&lt;br /&gt;The search results will look similar to this&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_nWyC8gWd544/RmRZA0qlrbI/AAAAAAAAADg/dHJDRYq32HQ/s1600-h/SearchResults.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_nWyC8gWd544/RmRZA0qlrbI/AAAAAAAAADg/dHJDRYq32HQ/s400/SearchResults.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5072276950998166962" /&gt;&lt;/a&gt;&lt;br /&gt;Select the necessary files, right-click and choose Check In from the menu.  Assuming you selected the correct files, the code should be updated without breaking the build.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-1994601683679878098?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/1994601683679878098/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/06/pseudo-changesets-in-sourcesafe.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1994601683679878098'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1994601683679878098'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/06/pseudo-changesets-in-sourcesafe.html' title='Pseudo-changesets In SourceSafe'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_nWyC8gWd544/RmRYt0qlrZI/AAAAAAAAADQ/YR1ch2OVxQY/s72-c/SelectProject.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-8899410669619602689</id><published>2007-05-22T13:38:00.002-05:00</published><updated>2009-10-18T11:16:21.653-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VS2005'/><title type='text'>VS2005 Item Templates</title><content type='html'>I've been spending a lot of time lately coding unit tests.  If I were writing tests for a class named Chainsaw, I would start with a blank class file, and modify til it looks something like this:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20 \cf2 using\cf0  System;\par ??\cf2 using\cf0  System.Collections.Generic;\par ??\cf2 using\cf0  System.Text;\par ??\cf2 using\cf0  NUnit.Framework;\par ??\cf2 using\cf0  Pedro.PowerTools;\par ??\par ??\cf2 namespace\cf0  Pedro.PowerTools.UnitTests\par ??\{\par ??    [\cf10 TestFixture\cf0 ]\par ??    \cf2 public\cf0  \cf2 class\cf0  \cf10 ChainsawUnitTests\par ??\cf0     \{\par ??        ChainsawAdapter myAdapter;\par ??\par ??        [\cf10 TestFixtureSetUp\cf0 ]\par ??        \cf2 public\cf0  \cf2 void\cf0  FixtureSetUp()\par ??        \{\par ??            myAdapter = \cf2 new\cf0  ChainsawAdapter();\par ??        \}\par ??    \}\par ??\}}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; NUnit.Framework;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; Pedro.PowerTools;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;namespace&lt;/span&gt; Pedro.PowerTools.UnitTests&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; [&lt;span style="color: teal;"&gt;TestFixture&lt;/span&gt;]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: teal;"&gt;ChainsawUnitTests&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ChainsawAdapter myAdapter;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; [&lt;span style="color: teal;"&gt;TestFixtureSetUp&lt;/span&gt;]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; FixtureSetUp()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; myAdapter = &lt;span style="color: blue;"&gt;new&lt;/span&gt; ChainsawAdapter();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;If you were to compare all of the TestFixtures in the assembly, you would find:&lt;br /&gt;&lt;ol&gt;&lt;li&gt; For the most part, I have the same 'using' statements in each&lt;/li&gt;&lt;li&gt; They all have the same namespace&lt;/li&gt;&lt;li&gt; The class name for each TestFixture is the class to test, followed by "UnitTests"&lt;/li&gt;&lt;li&gt; The data adapter name is the class to test, followed by "Adapter"&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;*Note - Yes, I'm testing several layers at once.  Call it efficient.  Call it lazy.  It's simply my preference.&lt;br /&gt;&lt;br /&gt;Though this isn't difficult to create by hand, there's an easier way - Item Templates.  What I want is a way to right-click on my Project, choose Add &amp;gt; New Item, pick "MyUnitTests" from the list, and have it magically create the basic code.  Turns out it's quite simple.&lt;br /&gt;&lt;br /&gt;Start by placing the above code in a .cs file.  Choose File &amp;gt; Export Template... from the menu.  In the Choose Template Type screen, select "Item template" and the project where the .cs file exists.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_nWyC8gWd544/RlM5KKudepI/AAAAAAAAACw/mgpEDJM4j7E/s1600-h/ChooseTemplateType.JPG"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5067456852562639506" src="http://3.bp.blogspot.com/_nWyC8gWd544/RlM5KKudepI/AAAAAAAAACw/mgpEDJM4j7E/s400/ChooseTemplateType.JPG" style="cursor: pointer; display: block; margin: 0px auto 10px; text-align: center;" /&gt;&lt;/a&gt;&lt;br /&gt;Click Next.  In the Select Item To Export screen, check the box beside the .cs file (ChainsawUnitTests.cs in my case.)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_nWyC8gWd544/RlM5bKudeqI/AAAAAAAAAC4/lrrYyNa2xu0/s1600-h/SelectItemToExport.JPG"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5067457144620415650" src="http://3.bp.blogspot.com/_nWyC8gWd544/RlM5bKudeqI/AAAAAAAAAC4/lrrYyNa2xu0/s400/SelectItemToExport.JPG" style="cursor: pointer; display: block; margin: 0px auto 10px; text-align: center;" /&gt;&lt;/a&gt;&lt;br /&gt;Click Next.  Under Select Item References, check the box for nunit.framework.  Ignore the warning.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_nWyC8gWd544/RlM5pauderI/AAAAAAAAADA/Wuqb2UiD_ZU/s1600-h/SelectItemReferences.JPG"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5067457389433551538" src="http://4.bp.blogspot.com/_nWyC8gWd544/RlM5pauderI/AAAAAAAAADA/Wuqb2UiD_ZU/s400/SelectItemReferences.JPG" style="cursor: pointer; display: block; margin: 0px auto 10px; text-align: center;" /&gt;&lt;/a&gt;&lt;br /&gt;Click Next.  On the Select Template Options screen, enter the Template name and description.  Make sure the box to "Display an explorer window..." is checked, and click Finish.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_nWyC8gWd544/RlM5vqudesI/AAAAAAAAADI/aOZ4dq2LRcw/s1600-h/SelectTemplateOptions.JPG"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5067457496807733954" src="http://1.bp.blogspot.com/_nWyC8gWd544/RlM5vqudesI/AAAAAAAAADI/aOZ4dq2LRcw/s400/SelectTemplateOptions.JPG" style="cursor: pointer; display: block; margin: 0px auto 10px; text-align: center;" /&gt;&lt;/a&gt;&lt;br /&gt;Once the template is generated, it will be placed in a .zip with the name of the template (for me, this is MyUnitTests.zip.)  This is a decent start, but we need to modify a few things.&lt;br /&gt;&lt;br /&gt;Open the .zip, and you should see the following files:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;_TemplateIcon.ico&lt;/li&gt;&lt;li&gt;ChainsawUnitTests.cs&lt;/li&gt;&lt;li&gt;MyTemplate.vstemplate&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Open MyTemplate.vstemplate.  Near the end of the file, you should see the following &amp;lt;ProjectItem&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&amp;lt;ProjectItem SubType="Code" TargetFileName="$fileinputname$.cs" ReplaceParameters="true"&amp;gt;ChainsawUnitTests.cs&amp;lt;/ProjectItem&amp;gt;&lt;/pre&gt;&lt;br /&gt;In VS2005, when you choose to create a new item for a project, it asks for a filename.  This filename, minus the extension, is placed in $fileinputname$.  For this template, however, I want to type in the class to test, and have it generate a filename using the classname, followed by "UnitTests.cs".  So let's change the line to&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&amp;lt;ProjectItem SubType="Code" TargetFileName="$fileinputname$UnitTests.cs" ReplaceParameters="true"&amp;gt;ChainsawUnitTests.cs&amp;lt;/ProjectItem&amp;gt;&lt;/pre&gt;&lt;br /&gt;Save the file, and let's open ChainsawUnitTests.cs.  It looks nearly identical to the original&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20 \cf2 namespace\cf0  $rootnamespace$\par ??\{\par ??    [\cf10 TestFixture\cf0 ]\par ??    \cf2 public\cf0  \cf2 class\cf0  $safeitemname$\par ??    \{\par ??        ChainsawAdapter myAdapter;\par ??\par ??        [\cf10 TestFixtureSetUp\cf0 ]\par ??        \cf2 public\cf0  \cf2 void\cf0  FixtureSetUp()\par ??        \{\par ??            myAdapter = \cf2 new\cf0  ChainsawAdapter();\par ??        \}\par ??    \}\par ??\}}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;namespace&lt;/span&gt; $rootnamespace$&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; [&lt;span style="color: teal;"&gt;TestFixture&lt;/span&gt;]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; $safeitemname$&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ChainsawAdapter myAdapter;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; [&lt;span style="color: teal;"&gt;TestFixtureSetUp&lt;/span&gt;]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; FixtureSetUp()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; myAdapter = &lt;span style="color: blue;"&gt;new&lt;/span&gt; ChainsawAdapter();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;In fact, the only changes made were to the namespace and classname.  Earlier, I mentioned wanting to type in the class to be tested, as opposed to the unit test class, when adding an item through the wizard.  This is because I want to replace "Chainsaw" in each instance of "ChainsawAdapter" with the class I'm testing.  As you may have already guessed, this comes from $fileinputname$.  Two replacements and we have the following:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20 \cf2 using\cf0  System;\par ??\cf2 using\cf0  System.Collections.Generic;\par ??\cf2 using\cf0  System.Text;\par ??\cf2 using\cf0  NUnit.Framework;\par ??\cf2 using\cf0  Pedro.PowerTools;\par ??\par ??\cf2 namespace\cf0  $rootnamespace$\par ??\{\par ??    [\cf10 TestFixture\cf0 ]\par ??    \cf2 public\cf0  \cf2 class\cf0  $safeitemname$\par ??    \{\par ??        $fileinputname$Adapter myAdapter;\par ??\par ??        [\cf10 TestFixtureSetUp\cf0 ]\par ??        \cf2 public\cf0  \cf2 void\cf0  FixtureSetUp()\par ??        \{\par ??            myAdapter = \cf2 new\cf0  $fileinputname$Adapter();\par ??        \}\par ??    \}\par ??\}}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; NUnit.Framework;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; Pedro.PowerTools;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;namespace&lt;/span&gt; $rootnamespace$&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; [&lt;span style="color: teal;"&gt;TestFixture&lt;/span&gt;]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; $safeitemname$&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; $fileinputname$Adapter myAdapter;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; [&lt;span style="color: teal;"&gt;TestFixtureSetUp&lt;/span&gt;]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; FixtureSetUp()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; myAdapter = &lt;span style="color: blue;"&gt;new&lt;/span&gt; $fileinputname$Adapter();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Save the changes and re-zip the files.  Drop the .zip in your custom ItemTemplates folder (the location can be found and/or modified in the VS Options dialog, under "Projects and Solutions" &amp;gt; "General."  Having done all that, go back to the test project in VS.  Right-click on the project and choose Add &amp;gt; New Item.  In the Templates dialog, you should see your new template near the bottom of the dialog.  Enter "DrillPress.cs" into the Name textbox and click Add.&lt;br /&gt;&lt;br /&gt;Assuming all went well, VS should generate DrillPressUnitTests.cs with the following content:&lt;br /&gt;&lt;!--{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20 \cf2 using\cf0  System;\par ??\cf2 using\cf0  System.Collections.Generic;\par ??\cf2 using\cf0  System.Text;\par ??\cf2 using\cf0  NUnit.Framework;\par ??\par ??\cf2 namespace\cf0  test1\par ??\{\par ??    [\cf10 TestFixture\cf0 ]\par ??    \cf2 public\cf0  \cf2 class\cf0  \cf10 DrillPressUnitTests\par ??\cf0     \{\par ??        DrillPressAdapter myAdapter;\par ??\par ??        [\cf10 TestFixtureSetUp\cf0 ]\par ??        \cf2 public\cf0  \cf2 void\cf0  FixtureSetUp()\par ??        \{\par ??            myAdapter = \cf2 new\cf0  DrillPressAdapter();\par ??        \}\par ??    \}\par ??\}}--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; System.Text;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;using&lt;/span&gt; NUnit.Framework;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&lt;span style="color: blue;"&gt;namespace&lt;/span&gt; test1&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;{&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; [&lt;span style="color: teal;"&gt;TestFixture&lt;/span&gt;]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: teal;"&gt;DrillPressUnitTests&lt;/span&gt;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; DrillPressAdapter myAdapter;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp;&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; [&lt;span style="color: teal;"&gt;TestFixtureSetUp&lt;/span&gt;]&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; FixtureSetUp()&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; myAdapter = &lt;span style="color: blue;"&gt;new&lt;/span&gt; DrillPressAdapter();&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;&amp;nbsp; &amp;nbsp; }&lt;/pre&gt;&lt;pre style="margin: 0px;"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-8899410669619602689?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/8899410669619602689/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/05/vs2005-item-templates.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8899410669619602689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8899410669619602689'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/05/vs2005-item-templates.html' title='VS2005 Item Templates'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_nWyC8gWd544/RlM5KKudepI/AAAAAAAAACw/mgpEDJM4j7E/s72-c/ChooseTemplateType.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-8234682387831136861</id><published>2007-05-18T08:41:00.001-05:00</published><updated>2009-05-19T13:41:50.223-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.Net'/><title type='text'>Reducing the size of ccnet.config</title><content type='html'>[Update 5/19/09: The latest version of CCNet makes this much easier by using a &lt;a href="http://confluence.public.thoughtworks.org/display/CCNET/Configuration+Preprocessor" title="Configuration Preprocessor (documentation)"&gt;Configuration Preprocessor&lt;/a&gt;.  I have a short writeup &lt;a href="http://automaticchainsaw.blogspot.com/2009/05/easier-way-to-manage-cruisecontrolnet.html" title="An easier way to manage CruiseControl.Net projects"&gt;here&lt;/a&gt;.]&lt;br /&gt;&lt;br /&gt;My demo setup only contains two projects, and there are already a few items that have been duplicated.  Items such as paths to SourceSafe and MSBuild executables.  As you add more projects, you find yourself copying and pasting lots of info.  This isn't recommended when writing code, so why should a config be any different?&lt;br /&gt;&lt;br /&gt;Let's take a look at the sourcecontrol blocks.  First, my still-empty custom tasks project&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;sourcecontrol&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="vss"&lt;/span&gt; &lt;span class="attr"&gt;autoGetSource&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&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;ssdir&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;c:\vss&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ssdir&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;executable&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;C:\Program Files\Microsoft Visual SourceSafe\ss.exe&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;executable&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;project&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$/MSBuild.Chainsaw.Tasks&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;project&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;workingDirectory&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;MSBuild.Chainsaw.Tasks&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;workingDirectory&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;sourcecontrol&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Then the MSBuild Community Tasks&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;sourcecontrol&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="vss"&lt;/span&gt; &lt;span class="attr"&gt;autoGetSource&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&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;ssdir&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;c:\vss&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ssdir&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;executable&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;C:\Program Files\Microsoft Visual SourceSafe\ss.exe&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;executable&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;project&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$/MSBuild.Community.Tasks&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;project&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;workingDirectory&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;MSBuild.Community.Tasks&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;workingDirectory&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;sourcecontrol&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Both &amp;lt;ssdir&amp;gt; and &amp;lt;executable&amp;gt; are identical.  To simplify things, add the following to the top of the config (above the opening &amp;lt;cruisecontrol&amp;gt;)&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;!&lt;/span&gt;&lt;span class="html"&gt;DOCTYPE&lt;/span&gt; &lt;span class="attr"&gt;cruisecontrol&lt;/span&gt; [&lt;br /&gt;    &lt;span class="attr"&gt;&amp;lt;&lt;/span&gt;!&lt;span class="attr"&gt;ENTITY&lt;/span&gt; &lt;span class="attr"&gt;ssCommon&lt;/span&gt; &lt;br /&gt;        "&lt;br /&gt;            &lt;span class="attr"&gt;&amp;lt;&lt;/span&gt;&lt;span class="attr"&gt;ssdir&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;c:\vss&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ssdir&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;executable&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;C:\Program Files\Microsoft Visual SourceSafe\ss.exe&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;executable&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;gt;&lt;/span&gt;&lt;br /&gt;]&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Now, those sections can be replaced with "&amp;amp;ssCommon;", like so&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;sourcecontrol&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="vss"&lt;/span&gt; &lt;span class="attr"&gt;autoGetSource&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="attr"&gt;&amp;amp;ssCommon;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;project&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$/MSBuild.Chainsaw.Tasks&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;project&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;workingDirectory&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;MSBuild.Chainsaw.Tasks&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;workingDirectory&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;sourcecontrol&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-8234682387831136861?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/8234682387831136861/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/05/reducing-size-of-ccnetconfig.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8234682387831136861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8234682387831136861'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/05/reducing-size-of-ccnetconfig.html' title='Reducing the size of ccnet.config'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-4520568139982044908</id><published>2007-05-18T08:29:00.000-05:00</published><updated>2008-11-13T07:50:48.951-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>Adding FxCop to the build</title><content type='html'>Most (though certainly not all) developers agree that code reviews are a useful step in the development process.  I won't go into specific benefits, as there are numerous &lt;a href="http://www.google.com/search?q=code+review"&gt;writings&lt;/a&gt; on the subject.&lt;br /&gt;&lt;br /&gt;One of the downsides, however, is that code reviews take time.  In fact, you could spend more time reviewing the code than you did writing it.  This is where &lt;a href="http://www.gotdotnet.com/Team/FxCop/"&gt;FxCop&lt;/a&gt; can help.  Though it won't catch problems with things like business rules, it does flag various issues related to performance, security, and code consistency/maintainability.  By adding it to the build, we get a decent code review with every checkin.&lt;br /&gt;&lt;br /&gt;For this demo, I downloaded the source for the &lt;a href="http://msbuildtasks.tigris.org"&gt;MSBuild Community Tasks&lt;/a&gt;.  Dropping this into SourceSafe, I set up a new project in CruiseControl.Net.&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;project&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="MSBuild.Community.Tasks"&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;sourcecontrol&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="vss"&lt;/span&gt; &lt;span class="attr"&gt;autoGetSource&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&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;ssdir&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;c:\vss&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ssdir&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;executable&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;C:\Program Files\Microsoft Visual SourceSafe\ss.exe&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;executable&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;project&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$/MSBuild.Community.Tasks&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;project&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;workingDirectory&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;MSBuild.Community.Tasks&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;workingDirectory&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;sourcecontrol&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;tasks&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;msbuild&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;executable&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;c:\winnt\Microsoft.Net\Framework\v2.0.50727\msbuild.exe&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;executable&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;projectFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;MSBuild.Community.Tasks\Source\MSBuild.Community.Tasks.sln&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;projectFile&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;buildArgs&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;/noconsolelogger &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;buildArgs&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;logger&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;c:\ThoughtWorks.CruiseControl.MsBuild.dll&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;logger&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;msbuild&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;tasks&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;publishers&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;statistics&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;xmllogger&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;publishers&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;project&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To add FxCop, we first need to create a project file.  Start FxCop.  From the menu, choose File &amp;gt; Save Project.  Out of laziness, I saved the file as c:\DefaultRules.FxCop.  Now to update the build file.  Below the &amp;lt;msbuild&amp;gt; section, add the following&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;exec&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;executable&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;C:\Program Files\Microsoft FxCop 1.35\FxCopCmd.exe&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;executable&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;buildArgs&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;/project:"C:\DefaultRules.FxCop" /fo /q /searchgac /file:"%CCNetWorkingDirectory%\MSBuild.Community.Tasks\Source\MSBuild.Community.Tasks\bin\Debug\MSBuild.Community.Tasks.dll" /out:FxCopLog.xml&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;buildArgs&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;exec&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Within the &amp;lt;publishers&amp;gt; section, add&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;merge&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;files&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;file&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;FxCopLog.xml&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;file&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;files&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;merge&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Save these changes and force a build - which fails.  Looking at the project report, it looks like everything should have worked.  We even have FxCop information on the page.  The Build Log, however, notes the missing dependency Microsoft.VisualStuido.SourceSafe.Interop.  The assembly isn't being copied to the build output folder.&lt;br /&gt;&lt;br /&gt;To fix, open the .sln in VisualStudio.  Under the project's References, select the missing interop and set the Copy Local property to True.  Checkin the modified project and you should see a successful build.&lt;br /&gt;&lt;br /&gt;Now we have FxCop info displaying on the Build Report.  We also have a detailed FxCop Report we can access from the Dashboard's menu.  Which is all well and good, but the reports aren't the most useful.  &lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_nWyC8gWd544/Rk2rnqudelI/AAAAAAAAACM/fDLNazFqdrc/s1600-h/build_report_fxcop.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_nWyC8gWd544/Rk2rnqudelI/AAAAAAAAACM/fDLNazFqdrc/s400/build_report_fxcop.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5065893853834082898" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_nWyC8gWd544/Rk2rx6udemI/AAAAAAAAACU/KrTwlY2JXts/s1600-h/fxcop_detailed_report.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_nWyC8gWd544/Rk2rx6udemI/AAAAAAAAACU/KrTwlY2JXts/s400/fxcop_detailed_report.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5065894029927742050" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Fortunately, you can download &lt;a href="http://confluence.public.thoughtworks.org/display/CCNETCOMM/XSL+Transforms"&gt;alternative stylesheets&lt;/a&gt; from the Thoughtworks site.  Unzip fxcop-summary.xsl and FxCopReport.xsl, and place in \webdashboard\xsl\ under the cc.net install directory.  Open FxCopReport.xsl in your favorite xml editor.  Replace all instances of&lt;br /&gt;&lt;br /&gt; src="images/&lt;br /&gt;&lt;br /&gt;with&lt;br /&gt;&lt;br /&gt; src="/ccnet/images/&lt;br /&gt;&lt;br /&gt;With the new reports in place, reload the dashboard.  If all goes as planned, you should see slightly improved FxCop reports.  Note these still aren't perfect, and there are likely others available on the web.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_nWyC8gWd544/Rk2r_qudenI/AAAAAAAAACc/wy3p1TUhxzo/s1600-h/build_report_fxcop_improved.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_nWyC8gWd544/Rk2r_qudenI/AAAAAAAAACc/wy3p1TUhxzo/s400/build_report_fxcop_improved.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5065894266150943346" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_nWyC8gWd544/Rk2sG6udeoI/AAAAAAAAACk/6W2gYGy_tQs/s1600-h/fxcop_detailed_report_improved.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_nWyC8gWd544/Rk2sG6udeoI/AAAAAAAAACk/6W2gYGy_tQs/s400/fxcop_detailed_report_improved.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5065894390704994946" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-4520568139982044908?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/4520568139982044908/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/05/adding-fxcop-to-build.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/4520568139982044908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/4520568139982044908'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/05/adding-fxcop-to-build.html' title='Adding FxCop to the build'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_nWyC8gWd544/Rk2rnqudelI/AAAAAAAAACM/fDLNazFqdrc/s72-c/build_report_fxcop.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-8347448770435273538</id><published>2007-05-07T08:23:00.000-05:00</published><updated>2007-07-24T08:38:34.024-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>Continuous Integration = Consistently Compileable Code</title><content type='html'>*Note: This is a continuation of my &lt;a href="http://automaticchainsaw.blogspot.com/2007/05/source-code-control-101.html"&gt;previous post&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;"Now that we have basic SS usage defined, where does CC.Net fit into the picture?"  Simple - it's what makes sure the code is in a usable state at all times.  &lt;br /&gt;&lt;br /&gt;Let's say you've finished creating the xml logger and checked everything in.  But say you forget to check in one file.  Everything builds on your machine, so you don't see the problem.  You're pulled from the project and another dev comes in later to continue.  Only, when he gets latest and attempts a compile, he receives a number of build errors.  Now he wastes time tracking down the cause of the problem - a missing or outdated file - and who might have that file.  Maybe you have the file, and he's wasted fifteen minutes.  But say you no longer have that file.  Now your colleague wasted that time, only to find out someone will have to recreate the work.&lt;br /&gt;&lt;br /&gt;Say instead you are working on code at the same time as another dev.  His job is to create the data and business layers, while you focus on the front end.  Somewhere during development, your colleague decides to modify a few method signatures.  Methods that you happen to be using.  And your colleague fails to warn you.  At some point you'll get latest, only to find that you can no longer compile your code.  It's likely that both of you must stop what you are working on and get the build back into a good state.  If there are only two of you, it might take twenty minutes.  As the number of devs on a project increases, the time required to restabilize the code likewise increases.  &lt;br /&gt;&lt;br /&gt;I previously worked on a project that had over a dozen developers.  Due somewhat to poor architecture, a break anywhere caused problems for the entire team.  The choices were to get latest and spend the morning stabilizing the build, or using outdated code, which meant integration later became even more difficult.&lt;br /&gt;&lt;br /&gt;Fortunately, these problems are easy to address using CruiseControl.Net.  Its job is to monitor the source code repository for any changes.  As soon as a change is made, CC.Net gets latest and rebuilds the code.  If the compile fails, everyone on the team is immediately (within a few minutes anyway) notified of the failure.  The dev who checked in the broken code can address the problem, and other team members know not to get latest for the moment.&lt;br /&gt;&lt;br /&gt;Regarding a broken build - if you aren't working on a fix, stay away from the repository.  Getting latest means the code on your box will no longer compile.  Checking in code may make things worse.  It's best to fix one build break before possibly introducing another.&lt;br /&gt;&lt;br /&gt;One more thing - if you break the build, fixing it should be your top priority.  If you check in code at the end of the day, hang around to verify the build is still good.  If you're in a hurry and can't wait for the build, don't check in the code.  You're more likely to forget something in your haste, increasing the odds of a break.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-8347448770435273538?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/8347448770435273538/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/05/continuous-integration-consistently.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8347448770435273538'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/8347448770435273538'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/05/continuous-integration-consistently.html' title='Continuous Integration = Consistently Compileable Code'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-4576731223203329734</id><published>2007-05-03T08:17:00.000-05:00</published><updated>2007-05-07T12:08:57.912-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SourceSafe'/><title type='text'>Source Code Control 101</title><content type='html'>At work, we're moving toward a more standardized development process.  Part of that standardization is on the usage of SourceSafe for source code control, and CruiseControl.Net for continuous integration (CI.)  The developers on the team come from a variety of backgrounds, and have different levels of experience with CI.  As the resident Build Guy, I've spent the most time with the tools and decided to lay out my thoughts on the process.&lt;br /&gt;&lt;br /&gt;*Note that these are not the only tools available, and with SourceSafe in particular there are certainly better options.  These are simply the tools we are working with.&lt;br /&gt;&lt;br /&gt;*Note also that I intended to cover both SS and CC.Net in a single post.  It ended up a bit longer than expected, so I'm splitting it into two entries.  This post is limited to source code control.  The next will dig into continuous integration.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;SourceSafe as version control&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;SourceSafe is not merely a way to back up code in case of hard drive failure.  It is a way to &lt;b&gt;revision&lt;/b&gt; your code.  It allows you to define checkpoints in completed work.  It provides an easy way to compare changes and roll back work if you find yourself going down the wrong path.&lt;br /&gt;&lt;br /&gt;For example, let's say you're updating a desktop application.  The current app generates a text file as output.  The goals for the next release are to enhance the logging and to generate xml instead of plain text.  To start, you decide to replace the existing log with xml.  Looking at the code, you realize the log messages are scattered throughout the entire app.  Unless each message is to be a self-contained element, this makes it difficult to generate well-formed xml.&lt;br /&gt;&lt;br /&gt;So you begin by creating a custom logger class.  This lets you track where in the xml tree you are, and ensures the output is well-formed.  After you've finished testing the logger, it's time to replace all of the old logging code with calls to the new class.  Right?&lt;br /&gt;&lt;br /&gt;Not just yet.  Now that you have working code it needs to be checked into SourceSafe.  "It doesn't do anything yet," you say?  True.  However, even though the class isn't used, it's still a functioning piece of code.  If you have to switch projects now, you know you can come back later and pick up with a working app.&lt;br /&gt;&lt;br /&gt;"What if you need to make a bug fix and release to production?"  The code isn't being used, remember?  So there shouldn't be an issue.&lt;br /&gt;&lt;br /&gt;With the logger checked into SourceSafe, it's time to replace the existing logging code.  At the start, everything seems fine.  But several hours into the process, you realize something.  It appears there's a bit of rarely-used code that logs info in a non-trivial, non-standard way.  No problem - you can update the xml logger to deal with the new info.  A few changes, which you of course check into SS, and you're back to replacing code.  But shortly thereafter, for whatever reason, you realize the logger changes shouldn't have been made.  Now what?&lt;br /&gt;&lt;br /&gt;Fortunately, the previous revision exists in SourceSafe.  It's easy to roll back the code and continue with your work.  But say you hadn't checked in the changes?  Instead, you would have had to manually modify the code until you were back to the point you were before.  If you've ever tried this, you know it's not often a trivial matter.  It certainly takes longer than the minute or two required for a SourceSafe rollback.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;SourceSafe allows collaboration&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Most software projects involve several team members contributing code.  This requires some means of getting updated code to the other developers.  It may also require a new developer to come in and pick up where another left off.&lt;br /&gt;&lt;br /&gt;Going back to the xml logger, say you have the logger code checked in and are pulled off to work on another project.  A new developer comes in and is tasked with replacing the old log code.  All the new guy has to do is get latest from SS and he can continue right where you left off.  Or maybe he comes in at the point where you've added to the logger (just before you realized those changes weren't necessary.)  Once the new guy figures out what's going on, it's as easy for him to roll back the code as it would have been for you.  There's a clear snapshot of where the code was before the change.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Checkin frequency&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;So you now see a few benefits of source code control.  The next question you may have is "How often do I check in my code?"  It depends on what you are doing, but the general answer is "Often."  A few times a week is typical, and multiple times a day is entirely possible.  The key is to find stopping points throughout the project.  &lt;br /&gt;&lt;br /&gt;Say you start coding a new multi-tiered application.  You begin by writing a few classes in the data layer, making sure you can connect to the database.  As soon as you have these compiling and running correctly, check the code in.  As you add new classes, check them in.  There's no reason to wait until the entire layer is code complete.&lt;br /&gt;&lt;br /&gt;Say instead you are working on a desktop application.  You begin by placing a few controls on a blank form.  Maybe you hook those controls to business logic.  Or maybe you prefer to setup the layout before making the code do anything useful.  Either way, each piece of logic and each set of controls define a discrete unit of work.  Hook up a couple buttons and check the code in.  Add logic to traverse the local hard drive, then check the code in.  With a bit of practice, you should recognize several good checkin opportunities on any given day.  That's not to say you need to check code in this often, but once a day is certainly possible.&lt;br /&gt;&lt;br /&gt;One final thought - before checking in the code, make sure it compiles and runs on your box.  Checking in code that doesn't compile only hinders development.  I'll cover this next time when I introduce continuous integration using CruiseControl.Net.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-4576731223203329734?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/4576731223203329734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/05/source-code-control-101.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/4576731223203329734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/4576731223203329734'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/05/source-code-control-101.html' title='Source Code Control 101'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-1889517850020726173</id><published>2007-04-27T17:19:00.000-05:00</published><updated>2008-11-13T07:50:49.163-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.Net'/><title type='text'>CC.Net - Project Report Page</title><content type='html'>In CC.Net, the Project Report page provides general information for a project.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_nWyC8gWd544/RjJ4XwdpXJI/AAAAAAAAAAM/uR6m-H_fKUA/s1600-h/ProjectReport.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_nWyC8gWd544/RjJ4XwdpXJI/AAAAAAAAAAM/uR6m-H_fKUA/s320/ProjectReport.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5058237681032060050" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Most of the items should be straightforward.  One thing you may notice is that the "View Statistics" link doesn't work.  Clicking the link gives an exception page stating "Object reference not set to an instance of an object."  The problem is that the &amp;lt;statistics&amp;gt; publisher wasn't specified.  Add the following to ccnet.config, within &amp;lt;project&amp;gt;&amp;lt;/project&amp;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;publishers&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;statistics&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;publishers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;Reload the page... "Unexpected exception caught on server."  The other pages now fail with the same error.  Not exactly the desired results.  Digging through the exception details, it appears the Log Publisher is missing.  Yet it was there a minute ago?  &lt;br /&gt;&lt;br /&gt;It turns out a default publisher is used if one isn't specified.  You can see this by removing the &amp;lt;publishers&amp;gt; section and clicking Project Configuration on the left.  This page gives the project's entire XML listing, both the entries in ccnet.config and any defaults you don't override.  A useful addition.&lt;br /&gt;&lt;br /&gt;Anyway, the publisher error is a simple fix:&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;publishers&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;statistics&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;xmllogger&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;publishers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;The pages again load.  On top of that, we now have statistics.  Or, will, as soon as we run another build.  Force a build, and you should see basic stats for the project.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_nWyC8gWd544/RjJ5QAdpXLI/AAAAAAAAAAc/XWegMTzV49I/s1600-h/Statistics.JPG"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_nWyC8gWd544/RjJ5QAdpXLI/AAAAAAAAAAc/XWegMTzV49I/s400/Statistics.JPG" border="0" alt=""id="BLOGGER_PHOTO_ID_5058238647399701682" /&gt;&lt;/a&gt;&lt;br /&gt;Nothing fancy, but it's a start.&lt;br /&gt;&lt;br /&gt;One more useful feature is the External Links item.  With this, you can easily add links to other resources - project documentation, bug server, etc.  Again, this is added within &amp;lt;project&amp;gt;&amp;lt;/project&amp;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;externalLinks&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;externalLink&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="Project Documentation"&lt;/span&gt; &lt;span class="attr"&gt;url&lt;/span&gt;&lt;span class="kwrd"&gt;="\\fileserver\project1\project.doc"&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;externalLinks&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-1889517850020726173?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/1889517850020726173/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/04/ccnet-project-report-page.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1889517850020726173'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/1889517850020726173'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/04/ccnet-project-report-page.html' title='CC.Net - Project Report Page'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_nWyC8gWd544/RjJ4XwdpXJI/AAAAAAAAAAM/uR6m-H_fKUA/s72-c/ProjectReport.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-3696539319065365311</id><published>2007-04-25T08:45:00.000-05:00</published><updated>2007-05-07T12:08:57.912-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='SourceSafe'/><title type='text'>CruiseControl.Net 101 - Projects</title><content type='html'>Last time, we installed CC.Net and created a blank project.  This time, we'll have that project actually *do* something.&lt;br /&gt;&lt;br /&gt;The first thing we need is something in source control to point to.  I happen to have a SourceSafe database at c:\vss, so I'll use that.  In SourceSafe (SS), I've created a new project, MSBuild.Chainsaw.Tasks.  There aren't any files in there currently, but we'll get to that shortly.  For now, let's add the following to ccnet.config, between the &amp;lt;project&amp;gt;&amp;lt;/project&amp;gt; tags:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;sourcecontrol&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="vss"&lt;/span&gt; &lt;span class="attr"&gt;autoGetSource&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&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;ssdir&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;c:\vss&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ssdir&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;executable&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;C:\Program Files\Microsoft Visual SourceSafe\ss.exe&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;executable&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;project&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$/MSBuild.Chainsaw.Tasks&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;project&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;workingDirectory&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;MSBuild.Chainsaw.Tasks&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;workingDirectory&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;sourcecontrol&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;This tells CC.Net to monitor the project $/MSBuild.Chainsaw.Tasks and any sub-projects.  If files are added or checked into the project, CC.Net will kick off a build.  At this point, we should test the updated project.&lt;br /&gt;&lt;br /&gt;Start Visual Studio 2005 (VS2005) and create a new C# Windows Class Library.  Give it a name of MSBuild.Chainsaw.Tasks.  Do not check the boxes to "Create directory for solution" or "Add to Source Control."  The former is unnecessary, the later would ruin my cleverly devised plan.  Once the project is generated, save the files and close VS2005.  Nope, we're not actually writing code.  We'll have to save that for another time.&lt;br /&gt;&lt;br /&gt;Back in SS, drag the solution file into $/MSBuild.Chainsaw.Tasks.  Open the CCTray app.  You should see the Last Build Label increment (CC.Net looks for changes once a minute, so you might have to wait a few seconds.)  The build still shows green - we haven't specified any tasks to perform.  Open Windows Explorer and browse to your CC.Net install folder.  Expand \server\Project 1\WorkingDirectory\MSBuild.Chainsaw.Tasks.  You should see the .sln file, meaning it's at least pulling the source correctly.&lt;br /&gt;&lt;br /&gt;To compile with MSBuild, there is one more piece we need.  By default, msbuild sends text output to the console.  CC.Net requires XML output from all of the build tasks.  You'll need to download &lt;a href="http://ccnetlive.thoughtworks.com/MSBuildXmlLogger-Builds/"&gt;ThoughtWorks.CruiseControl.MSBuild.dll&lt;/a&gt;.  Out of shear laziness, I place this file in the root of the c: drive.  &lt;br /&gt;&lt;br /&gt;With that out of the way, let's go back to ccnet.config.  Add the following to the file:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;tasks&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;msbuild&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;executable&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;c:\winnt\Microsoft.Net\Framework\v2.0.50727\msbuild.exe&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;executable&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;projectFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;MSBuild.Chainsaw.Tasks\MSBuild.Chainsaw.Tasks.sln&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;projectFile&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;buildArgs&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;/noconsolelogger &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;buildArgs&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;logger&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;c:\ThoughtWorks.CruiseControl.MsBuild.dll&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;logger&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;msbuild&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;tasks&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Note: The &amp;lt;executable&amp;gt; tag is necessary if you're running on Windows2000.  If you're on WinXP, it isn't required.&lt;br /&gt;&lt;br /&gt;Save the config and go back to CCTray.  Hmm... Nothing happened.  That's of course by design - nothing's changed in SS.  To test the config change we need to force a build.  This can be done with the Force button in the Dashboard, or by right-clicking the project in CCTray and choosing Force Build.&lt;br /&gt;&lt;br /&gt;After the build runs, the CCTray icon will be red.  In the Dashboard, the Last Build Status shows "Failure."  To look at the details, open Project 1 in the Dashboard.  Select the most recent build.  The Build Report for this build doesn't tell us much (we'll fix this shortly.)  Click "View Build Log" from the menu on the left.  This is the raw XML output from the build.  If you look in the &amp;lt;msbuild&amp;gt; section, you should see a line that includes 'The project file "MSBuild.Chainsaw.Tasks.csproj" was not found.'  Not surprising since we didn't add it to SS yet.&lt;br /&gt;&lt;br /&gt;Before we fix this error, let's modify the report to show MSBuild output.  In Windows Explorer, browse to \webdashboard in the install folder.  Open dashboard.config.  Locate the following:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;buildPlugins&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;buildReportBuildPlugin&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;xslFileNames&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;xslFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;xsl\header.xsl&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;xslFile&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;xslFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;xsl\modifications.xsl&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;xslFile&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;xslFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;xsl\compile.xsl&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;xslFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Beneath this, add the line:&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;                &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;xslFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;xsl\compile-msbuild.xsl&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;xslFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;This will format msbuild output within the build report.  Note that the ordering of the .xsl files determines the ordering in the report.  Also, if there are items you aren't interested in, those lines can be removed from the config.&lt;br /&gt;&lt;br /&gt;After you save the config, force another build and verify that you now have two additional sections in the Build Report - Errors and Warnings.&lt;br /&gt;&lt;br /&gt;Now to fix the build error.  Add the remaining files from the MSBuild.Chainsaw.Tasks project to SS.  Having done that, we wait patiently while CC.Net kicks off another build.  Assuming all the files were added, the build should complete successfully.&lt;br /&gt;&lt;br /&gt;Sorry for the lengthy post.  I could have stopped somewhere in the middle, but the one thing I can't stand is a broken build.  My co-workers can attest to this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-3696539319065365311?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/3696539319065365311/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/04/cruisecontrolnet-101-projects.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/3696539319065365311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/3696539319065365311'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/04/cruisecontrolnet-101-projects.html' title='CruiseControl.Net 101 - Projects'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6566548306419873706.post-281307951734091412</id><published>2007-04-20T17:27:00.000-05:00</published><updated>2007-05-07T12:08:03.066-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CruiseControl.Net'/><title type='text'>CruiseControl.Net 101 - Installation</title><content type='html'>My plan is to start with few entries covering the basic setup, configuration and usage of CC.Net.  This way, if I'm hit by a bus, someone else at work can take over as the BuildGuy.  Or they can wipe the machine and turn it into an mp3 server.  Their choice.&lt;br /&gt;&lt;br /&gt;The server install (v1.2.1) is rather straightforward, though you'll want IIS loaded beforehand.  During the install, check the boxes to install as a service, and to create a virtual directory in IIS.  Note the service (CruiseControl.NET Server) is set to Manual startup, and eventually needs to be switched to Automatic.  While configuring projects, however, you may find it easier to debug running the console.&lt;br /&gt;&lt;br /&gt;Once installed, start the console or service and point your browser to &lt;a href="http://localhost/ccnet/"&gt;http://localhost/ccnet/&lt;/a&gt;.  If the Dashboard is displayed, good job.  Your install went smoother than mine.  Because I installed IIS after the .NET framework, I received an error stating "Failed to access IIS metabase."  Running "aspnet_regiis -i -enable" took care of the issue.&lt;br /&gt;&lt;br /&gt;Now that we have the server running, we need a project.  Open ccnet.config - located in "C:\Program Files\CruiseControl.NET\server" on my box.  Replace the contents with:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="font-family:courier new;"&gt;&amp;lt;cruisecontrol&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;     &amp;lt;project name="Project 1"&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;     &amp;lt;/project&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&amp;lt;/cruisecontrol&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;No, it doesn't do anything - I'm not in any hurry.  Save the file and go back to the Dashboard.  You should now see "Project 1" in the list.&lt;br /&gt;&lt;br /&gt;With that in place, install the CC.NET TrayApp.  One installed, we want to add Project 1 to the list of monitored projects.  In CCTray, go to File &gt; Settings.  On the Build Projects tab, click Add.  Click Add Server.  The Build Server dialog now visible provides three methods of connecting to the server.  Either the dashboard or remoting options will work.&lt;br /&gt;&lt;br /&gt;Once you've selected a connection method, the Project list now contains the build server and a single project (Project 1.)  Select the project and click OK.  Click OK to close the settings, and you should now see the status of the project.  This will match the info displayed on the Dashboard.&lt;br /&gt;&lt;br /&gt;Well, that was fun.  Maybe next time we'll have the server do something useful.  But I make no promises...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6566548306419873706-281307951734091412?l=automaticchainsaw.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://automaticchainsaw.blogspot.com/feeds/281307951734091412/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/04/cruisecontrolnet-101-installation.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/281307951734091412'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6566548306419873706/posts/default/281307951734091412'/><link rel='alternate' type='text/html' href='http://automaticchainsaw.blogspot.com/2007/04/cruisecontrolnet-101-installation.html' title='CruiseControl.Net 101 - Installation'/><author><name>PedroG</name><uri>http://www.blogger.com/profile/04615429057058350641</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry></feed>
