<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DkMDQng8eSp7ImA9WhRWF00.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976</id><updated>2012-01-04T21:14:33.671+02:00</updated><category term="CodeReviews" /><category term="C#" /><category term="Learning" /><category term="SDLC" /><category term="TeamCity" /><category term="Profiling" /><category term="ContinuousIntegration" /><category term="Standards" /><category term="FxCop" /><category term="Localization" /><category term="Pragma" /><category term="Jobs" /><category term="Tools" /><category term="DotNET" /><category term="Rant" /><category term="CodeAnalysis" /><category term="OnKey" /><category term="TeamWork" /><category term="Metrics" /><category term="Silverlight" /><category term="Books" /><title>From The Software Development Trenches</title><subtitle type="html">Thoughts on software development</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://fromthedevtrenches.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>27</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/FromTheSoftwareDevelopmentTrenches" /><feedburner:info uri="fromthesoftwaredevelopmenttrenches" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by/2.0/" /><entry gd:etag="W/&quot;DUYFQXc5cCp7ImA9WhZbGEQ.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-1129869885422130369</id><published>2011-06-24T08:31:00.001+02:00</published><updated>2011-06-24T08:31:50.928+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-24T08:31:50.928+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Rant" /><category scheme="http://www.blogger.com/atom/ns#" term="DotNET" /><title>Elementary, my dear Watson</title><content type="html">&lt;p&gt;&lt;img style="border-right-width: 0px; margin: 0px 10px 0px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" align="left" src="http://lh4.ggpht.com/-D0kzUy9vJ24/TgQvVYUe8aI/AAAAAAAAAvA/QA9BVEgjLvQ/image%25255B4%25255D.png?imgmax=800" width="135" height="201"&gt; &lt;/p&gt; &lt;p&gt;&amp;lt;rant&amp;gt; I don’t know about any other .NET developer out there, but I’m finding the &lt;a href="http://www.zdnet.com/blog/microsoft/microsoft-splits-up-its-xaml-team-whats-the-fallout/9807" target="_blank"&gt;current&lt;/a&gt; &lt;a href="http://www.zdnet.com/blog/microsoft/under-the-windows-8-hood-questions-and-answers-from-the-trenches/9738" target="_blank"&gt;speculation&lt;/a&gt; with regards to what’s going to happen with vNext of the .NET developer tool stack to be totally frustrating to say the least.&amp;nbsp; This is causing so much angst and damage in the .NET developer community.&amp;nbsp; The uncertainty about what’s going to happen with technology stacks like SL, WPF etc. and the unwillingness of MS to be open about their future is killing a lot of momentum and goodwill and just adding more fuel onto the “oh-what-is-MS-up-to-now-again” discussions.&amp;nbsp; Yes, I know, all will become crystal clear at the &lt;a href="http://www.zdnet.com/blog/microsoft/microsoft-if-we-build-a-new-developers-conference-will-they-come/9584" target="_blank"&gt;BUILD conference&lt;/a&gt; somewhere in September, but why didn’t MS keep quiet until then?&amp;nbsp; Figure out what you want to do with the different technology stacks, restructure and get enough prototyping done BEFORE starting to communicate to the developer community.&amp;nbsp; Why even mention something like “&lt;a href="http://www.zdnet.com/blog/microsoft/windows-8-more-than-just-windows-phone-on-your-pc/9592" target="_blank"&gt;HTML 5 and JavaScript is the way to go&lt;/a&gt;” with the first &lt;a href="http://www.microsoft.com/presspass/features/2011/jun11/06-01corporatenews.aspx" target="_blank"&gt;demo preview of Windows 8&lt;/a&gt;.&amp;nbsp; Surely MS should have expected the reaction by developers wanting to know what the future holds for the other technology stacks?&amp;nbsp; Anyway, I hope MS gets this right and that v1 of the next, seemingly &lt;a href="http://www.zdnet.com/blog/microsoft/more-on-microsoft-jupiter-and-what-it-means-for-windows-8/8373" target="_blank"&gt;consolidated UX platform&lt;/a&gt;, does not set us back another 2/3 years in waiting for it to become a really usable technology stack. &amp;lt;/rant&amp;gt;&lt;/p&gt; &lt;p&gt;So until BUILD in September we are left to act as Sherlock Holmes – looking at information surfacing via leaked e-mails and other blog posts.&amp;nbsp; Alternatively we can just let it be and hope that everything will indeed fall together in a big “ah-hah moment” come September.&amp;nbsp; I just hope that an already fatigued .NET developer community will have enough energy left to buy into whatever MS is going to preach next and that it will be “Elementary, my dear Watson.&amp;nbsp; Elementary indeed.”&amp;nbsp; Time to get some rest before September then &lt;img alt="Disappointed" src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/what_smile.gif"&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-1129869885422130369?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/yfsxSRG57T8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/1129869885422130369/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2011/06/elementary-my-dear-watson.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/1129869885422130369?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/1129869885422130369?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/yfsxSRG57T8/elementary-my-dear-watson.html" title="Elementary, my dear Watson" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/-D0kzUy9vJ24/TgQvVYUe8aI/AAAAAAAAAvA/QA9BVEgjLvQ/s72-c/image%25255B4%25255D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2011/06/elementary-my-dear-watson.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQHRnk8eCp7ImA9WhZbFUg.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-4070416158032874451</id><published>2011-06-17T08:03:00.001+02:00</published><updated>2011-06-20T08:45:37.770+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-20T08:45:37.770+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Localization" /><category scheme="http://www.blogger.com/atom/ns#" term="DotNET" /><title>Managing .NET RESX Duplication – Part 2: Identifying Resource Duplication</title><content type="html">&lt;p&gt;&lt;strong&gt;Update 20/06/2011: Fixed bug in C# snippet that shows how to process list of resources files&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;img style="border-right-width: 0px; margin: 0px 20px 10px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Globe" border="0" alt="Globe" align="left" src="http://lh3.ggpht.com/-hVH66EFKOfo/TfrtuDY8nEI/AAAAAAAAAu0/TWS_MfI275g/Globe4.jpg?imgmax=800" width="142" height="144"&gt; This is the second post in a &lt;a href="http://fromthedevtrenches.blogspot.com/2011/04/managing-net-resx-duplication-part-1.html" target="_blank"&gt;three part series of posts&lt;/a&gt; where I look at a possible solution for managing duplication of resources between your .NET RESX files.&amp;nbsp; In &lt;a href="http://fromthedevtrenches.blogspot.com/2011/04/managing-net-resx-duplication-part-1.html" target="_blank"&gt;part 1&lt;/a&gt; I covered the overall solution requirements and design to fit our environment.&amp;nbsp; In this second part I’m going to delve straight into the custom MSBuild task that identifies the resource duplication across the resource files being used in our code base.&amp;nbsp; As mentioned, the solution consists out of two distinct phases.&amp;nbsp; Phase 1 &lt;strong&gt;identifies&lt;/strong&gt; the resources duplicates across the .RESX files.&amp;nbsp; Phase 2 attempts to &lt;strong&gt;minimize&lt;/strong&gt; the duplication in these files.&amp;nbsp; We decided to implement both these phases as custom MSBuild tasks that run as part of every solution compilation to facilitate our &lt;em&gt;Continuously Execute&lt;/em&gt; requirement.&lt;/p&gt;&lt;a name='more'&gt;&lt;/a&gt; &lt;h2&gt;DATASTRUCTURES&lt;/h2&gt; &lt;p&gt;Before looking at the custom task, let’s consider the algorithm and data structures that we will use to track the resource duplication.&amp;nbsp; The MSBuild task will receive as input a list of .RESX files that it will scan for duplication.&amp;nbsp; Whilst scanning through the files it will build up a dictionary containing all the resource entries for a single key. This can be visualized as illustrated below:&lt;/p&gt; &lt;p&gt;&amp;nbsp;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-THj6cBKe3a8/TfruFKnincI/AAAAAAAAAu4/aNQ98fzG3qM/image8.png?imgmax=800" width="421" height="193"&gt; &lt;/p&gt; &lt;p&gt;For every entry found, we need to track the File as well as the &lt;a href="http://msdn.microsoft.com/en-us/library/system.resources.resxdatanode.aspx" target="_blank"&gt;ResXDataNode&lt;/a&gt; found and for this we use a &lt;strong&gt;ResXDuplicateEntry&lt;/strong&gt; class:&lt;/p&gt; &lt;p&gt;&lt;/p&gt; &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:ca6dcab6-c6b4-48f8-a1d7-4d6ee2a81f46" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 686px; height: 400px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXDuplicateEntry
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#region&lt;/span&gt;&lt;span style="color: #000000;"&gt; Properties&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; File { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt;; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt;; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXDataNode Node { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt;; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt;; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; &lt;span style="color: #000000;"&gt;      
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#endregion&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#region&lt;/span&gt;&lt;span style="color: #000000;"&gt; Methods&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; GetLanguageNeutralFile(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; file, &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; culture)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;14&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; culture &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;?&lt;/span&gt;&lt;span style="color: #000000;"&gt; file : file.Replace(&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;.&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;+&lt;/span&gt;&lt;span style="color: #000000;"&gt; culture &lt;/span&gt;&lt;span style="color: #000000;"&gt;+&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;.resx&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;.resx&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;15&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;16&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;17&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; GetLanguageSpecificFile(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; file, &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; culture)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;18&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;19&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; culture &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;?&lt;/span&gt;&lt;span style="color: #000000;"&gt; file : file.Replace(&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;.resx&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;.&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;+&lt;/span&gt;&lt;span style="color: #000000;"&gt; culture &lt;/span&gt;&lt;span style="color: #000000;"&gt;+&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;.resx&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;20&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;21&lt;/span&gt; &lt;span style="color: #000000;"&gt;      
&lt;/span&gt;&lt;span style="color: #008080;"&gt;22&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#endregion&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;23&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;24&lt;/span&gt; &lt;span style="color: #000000;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;A single resource key can contain multiple resource entries.&amp;nbsp;&amp;nbsp; We use a &lt;strong&gt;ResXDuplicate&lt;/strong&gt; container to track all the ResXDuplicateEntry instances for a single resource key across the different files:&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:bcd97afd-a1eb-4c67-875e-89a4eb722187" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 686px; height: 663px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXDuplicate
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;readonly&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXDuplicateComparer comparer &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXDuplicateComparer();
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXDuplicate(TaskLoggingHelper log, &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; culture)
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; &lt;span style="color: #000000;"&gt;          Log &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; log;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt; &lt;span style="color: #000000;"&gt;          Culture &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; culture;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt; &lt;span style="color: #000000;"&gt;          Entries &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDuplicateEntry&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#region&lt;/span&gt;&lt;span style="color: #000000;"&gt; Properties&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;14&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; Count
&lt;/span&gt;&lt;span style="color: #008080;"&gt;15&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;16&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; Entries.Count; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;17&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;18&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;19&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; Culture { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt;; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt;; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;20&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;21&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; Key
&lt;/span&gt;&lt;span style="color: #008080;"&gt;22&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;23&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; Node.Name; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;24&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;25&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;26&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXDataNode Node
&lt;/span&gt;&lt;span style="color: #008080;"&gt;27&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;28&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; Entries[&lt;/span&gt;&lt;span style="color: #800080;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;].Node; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;29&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;30&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;31&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDuplicateEntry&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; Entries { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt;; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt;; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;32&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;33&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#endregion&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;34&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;35&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#region&lt;/span&gt;&lt;span style="color: #000000;"&gt; Methods&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;36&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;37&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; AddEntry(ResXDataNode node, &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; file)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;38&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;39&lt;/span&gt; &lt;span style="color: #000000;"&gt;          Entries.Add(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXDuplicateEntry {Node &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; node, File &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; file});
&lt;/span&gt;&lt;span style="color: #008080;"&gt;40&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;41&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;42&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#endregion&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;43&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Once we have scanned through all the resource files and build up our dictionary of resource keys with resource entries, we identify the list of duplicates by filtering the dictionary to all entries containing more than one ResxDuplicateEntry class.&amp;nbsp; For these duplicates, we then proceed to compare the individual entries for the same key across different files to each other.&amp;nbsp; For this we created a few extensions methods on the ResXDataNode class to make reading and setting the values a bit easier.&lt;/p&gt;
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:fc73f9a7-a548-4a57-b42a-327c3146cc26" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 686px; height: 299px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXExtensions
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; GetValue(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXDataNode node)
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; node.GetValue((ITypeResolutionService)&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;).ToString().Trim();
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXDataNode Tag(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXDataNode node, &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; tagToken)
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;          ResXDataNode taggedNode &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXDataNode(node.Name, tagToken);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; taggedNode;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;14&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;bool&lt;/span&gt;&lt;span style="color: #000000;"&gt; IsTagged(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXDataNode node, &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; tagToken)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;15&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;16&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; GetValue(node).StartsWith(tagToken);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;17&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;18&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;19&lt;/span&gt; &lt;span style="color: #000000;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;When comparing the different values for the same key, we can one of two outcomes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;All the entries match – If all the entries match we can safely report all of them as duplicates 
&lt;li&gt;Some entries differ – If only some entries match up, we first find the value amongst the entries that are duplicated the most, and use that to report the number of duplicates identified &lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;We use a &lt;strong&gt;ResXStatsSummary&lt;/strong&gt; class to report the statistics of the resources scan.
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:f271c1cb-796c-4f16-9a30-04f57f63f7a0" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 686px; height: 522px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;struct&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXStatsSummary
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#region&lt;/span&gt;&lt;span style="color: #000000;"&gt; Properties&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; Duplicates { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt;; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt;; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; NotDuplicates
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; Scanned &lt;/span&gt;&lt;span style="color: #000000;"&gt;-&lt;/span&gt;&lt;span style="color: #000000;"&gt; Duplicates; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; Scanned { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt;; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt;; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; DuplicatesTagged { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt;; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt;; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;14&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;15&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; TotalResourcesToTranslate
&lt;/span&gt;&lt;span style="color: #008080;"&gt;16&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;17&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; (Duplicates &lt;/span&gt;&lt;span style="color: #000000;"&gt;-&lt;/span&gt;&lt;span style="color: #000000;"&gt; DuplicatesTagged) &lt;/span&gt;&lt;span style="color: #000000;"&gt;+&lt;/span&gt;&lt;span style="color: #000000;"&gt; NotDuplicates; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;18&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;19&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;20&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#endregion&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;21&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;22&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#region&lt;/span&gt;&lt;span style="color: #000000;"&gt; Methods&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;23&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;24&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;override&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; ToString()
&lt;/span&gt;&lt;span style="color: #008080;"&gt;25&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;26&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; String.Format(CultureInfo.InvariantCulture,
&lt;/span&gt;&lt;span style="color: #008080;"&gt;27&lt;/span&gt; &lt;span style="color: #000000;"&gt;              &lt;/span&gt;&lt;span style="color: #800000;"&gt;@&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Scanned: {1} resource(s){0}Unique: {3} resource(s){0}Duplicates: {4} resource(s){0}Duplicates tagged: {5} resource(s){0}Total to translate: {2} resource(s)&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;,
&lt;/span&gt;&lt;span style="color: #008080;"&gt;28&lt;/span&gt; &lt;span style="color: #000000;"&gt;              Environment.NewLine, Scanned, TotalResourcesToTranslate, NotDuplicates, Duplicates, DuplicatesTagged);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;29&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;30&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;31&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#endregion&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;32&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;&lt;/p&gt;
&lt;h2&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2&gt;Scanning Resource Files&lt;/h2&gt;
&lt;p&gt;Now that we’ve covered the basis of the scanning algorithm and the data structures used for storing the results, let’s look at the actual code that scans the resources files to build the dictionary of ResXDuplicate entries.&amp;nbsp;&amp;nbsp; All the MSBuild tasks that we create inherit from a ResXTaskBase class that contains the shared scanning logic. Here is the definition of the class along with its member variables.&amp;nbsp;&amp;nbsp; Notice the list of files is received as an input parameter for the MSBuild task on line 19.&amp;nbsp; Also notice the dictionary of ResxDuplicate entries that will contain the result of scanning all the resource files on line 10.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:6e00fa0b-5da7-4f00-ba77-9dbd7aa136b9" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 675px; height: 363px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;abstract&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXTaskBase : Task
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;span style="color: #000000;"&gt;    {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;const&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; TagToken &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;[## SHARED ##]&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;protected&lt;/span&gt;&lt;span style="color: #000000;"&gt; IEnumerable&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDuplicate&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; _distinct;        
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;protected&lt;/span&gt;&lt;span style="color: #000000;"&gt; IEnumerable&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDuplicate&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; _duplicates;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;protected&lt;/span&gt;&lt;span style="color: #000000;"&gt; IEnumerable&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDuplicate&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; _notDistinct;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Dictionary keyed on Resource Key that contains all the files containing an entry for the same key&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;protected&lt;/span&gt;&lt;span style="color: #000000;"&gt; Dictionary&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;, ResXDuplicate&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; _processed;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;protected&lt;/span&gt;&lt;span style="color: #000000;"&gt; Dictionary&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;, List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDataNode&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; _distinctFileDuplicates &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; Dictionary&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;, List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDataNode&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;protected&lt;/span&gt;&lt;span style="color: #000000;"&gt; Dictionary&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;, List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDataNode&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; _mostUsedFileDuplicates &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; Dictionary&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;, List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDataNode&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;14&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;protected&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXStatsSummary _stats;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;15&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;16&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#region&lt;/span&gt;&lt;span style="color: #000000;"&gt; Properties&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;17&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;18&lt;/span&gt; &lt;span style="color: #000000;"&gt;        [Required]
&lt;/span&gt;&lt;span style="color: #008080;"&gt;19&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; ITaskItem[] SourceFiles { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt;; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt;; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;20&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;21&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#endregion&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Next up is the scanning algorithm.&amp;nbsp; As we want to use the same scanning algorithm to scan all the files specific to a culture, we make sure that we can specify what culture to take into account as a parameter.&amp;nbsp; By default the culture will be &lt;em&gt;null&lt;/em&gt; which implies that all the culture neutral resource files will be scanned:&lt;/p&gt;
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:1876639d-1b48-4cc7-a5d3-2c8aee070f6a" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 686px; height: 22px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;protected&lt;/span&gt;&lt;span style="color: #000000;"&gt; Dictionary&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;, ResXDuplicate&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; ParseResxFiles(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; culture &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;p&gt;We start the scanning algorithm by first building up the list of resource files to scan by taking the culture parameter into account.&amp;nbsp; If we are for example scanning the Brazilian Portuguese resources, we make sure that we add the &lt;em&gt;pt-Br&lt;/em&gt; culture onto the file name being processed:&lt;/p&gt;
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:e40a7716-8738-4058-b177-ebff4ff96c06" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 686px; height: 141px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;    Dictionary&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;, ResXDuplicate&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; processed &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; Dictionary&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;, ResXDuplicate&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;2&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;3&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Build a list of files to process&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;4&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;    List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; resxFiles &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;5&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;foreach&lt;/span&gt;&lt;span style="color: #000000;"&gt; (var sourceFile &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;in&lt;/span&gt;&lt;span style="color: #000000;"&gt; SourceFiles)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;6&lt;/span&gt; &lt;span style="color: #000000;"&gt;    {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;7&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; fileName &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXDuplicateEntry.GetLanguageSpecificFile(sourceFile.ItemSpec, culture);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;8&lt;/span&gt; &lt;span style="color: #000000;"&gt;        resxFiles.Add(fileName);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;9&lt;/span&gt; &lt;span style="color: #000000;"&gt;    }&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;p&gt;Once we have the actual list of file names to process, we can now simply run through the list of files, reading all the entries to populate our dictionary with the respective ResXDuplicate entries:&lt;/p&gt;
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:24db4769-5a1d-4704-aacf-ab4ab5b8728e" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 686px; height: 376px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;foreach&lt;/span&gt;&lt;span style="color: #000000;"&gt; (var resxFile &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;in&lt;/span&gt;&lt;span style="color: #000000;"&gt; resxFiles)
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;span style="color: #000000;"&gt;    {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (&lt;/span&gt;&lt;span style="color: #000000;"&gt;!&lt;/span&gt;&lt;span style="color: #000000;"&gt;File.Exists(resxFile))
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #000000;"&gt;            &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;continue&lt;/span&gt;&lt;span style="color: #000000;"&gt;;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;using&lt;/span&gt;&lt;span style="color: #000000;"&gt; (ResXResourceReader reader &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXResourceReader(resxFile))
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; &lt;span style="color: #000000;"&gt;        {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt; &lt;span style="color: #000000;"&gt;            reader.UseResXDataNodes &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;true&lt;/span&gt;&lt;span style="color: #000000;"&gt;;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt; &lt;span style="color: #000000;"&gt;            Log.LogMessage(MessageImportance.Low, &lt;/span&gt;&lt;span style="color: #800000;"&gt;@&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Scanning {0}...&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, Path.GetFileName(resxFile));
&lt;/span&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;            &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;foreach&lt;/span&gt;&lt;span style="color: #000000;"&gt; (DictionaryEntry entry &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;in&lt;/span&gt;&lt;span style="color: #000000;"&gt; reader)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt; &lt;span style="color: #000000;"&gt;            {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt; &lt;span style="color: #000000;"&gt;                &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; key &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; entry.Key.ToString();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;14&lt;/span&gt; &lt;span style="color: #000000;"&gt;                ResXDataNode node &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; (ResXDataNode) entry.Value;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;15&lt;/span&gt; &lt;span style="color: #000000;"&gt;                ResXDuplicate duplicate;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;16&lt;/span&gt; &lt;span style="color: #000000;"&gt;                &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (&lt;/span&gt;&lt;span style="color: #000000;"&gt;!&lt;/span&gt;&lt;span style="color: #000000;"&gt;processed.TryGetValue(key, &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;out&lt;/span&gt;&lt;span style="color: #000000;"&gt; duplicate))
&lt;/span&gt;&lt;span style="color: #008080;"&gt;17&lt;/span&gt; &lt;span style="color: #000000;"&gt;                {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;18&lt;/span&gt; &lt;span style="color: #000000;"&gt;                    duplicate &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXDuplicate(Log, culture);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;19&lt;/span&gt; &lt;span style="color: #000000;"&gt;                    processed.Add(key, duplicate);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;20&lt;/span&gt; &lt;span style="color: #000000;"&gt;                }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;21&lt;/span&gt; &lt;span style="color: #000000;"&gt;                duplicate.AddEntry(node, resxFile);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;22&lt;/span&gt; &lt;span style="color: #000000;"&gt;            }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;23&lt;/span&gt; &lt;span style="color: #000000;"&gt;        }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;24&lt;/span&gt; &lt;span style="color: #000000;"&gt;    }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;25&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; processed;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;With the dictionary now fully populated with all resource entries, we can proceed to filtering out the duplicate entries.&amp;nbsp; As mentioned, when doing the filtering we identify for every resource key whether all the entries contain the same value - i.e. is distinct or not.&amp;nbsp; For this we use the IsDistinct method created on the ResXDuplicate class:&lt;/p&gt;
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:da10b52a-7e11-478e-a0ba-154e77a513ff" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 682px; height: 108px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;bool&lt;/span&gt;&lt;span style="color: #000000;"&gt; IsDistinct()
&lt;/span&gt;&lt;span style="color: #008080;"&gt;2&lt;/span&gt; &lt;span style="color: #000000;"&gt;    {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;3&lt;/span&gt; &lt;span style="color: #000000;"&gt;        List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDuplicateEntry&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; notAlreadyShared &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; Entries.Where(x &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;!&lt;/span&gt;&lt;span style="color: #000000;"&gt;x.Node.IsTagged(ResXTaskBase.TagToken)).ToList();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;4&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; notAlreadyShared.Count &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;||&lt;/span&gt;&lt;span style="color: #000000;"&gt; notAlreadyShared.Distinct(comparer).Count() &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;5&lt;/span&gt; &lt;span style="color: #000000;"&gt;    }&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;p&gt;We first ignored all nodes that have been tagged as shared (we’ll cover this in the next post) and then use our ResXDuplicateComparer and a LINQ query to check whether all entries in the list match.&amp;nbsp; We stored the results of our filtering into two separate lists of ResXDuplicate entries:&lt;/p&gt;
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:0e33c1d3-be9d-4b32-9644-7368824adc70" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 612px; height: 217px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;override&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;bool&lt;/span&gt;&lt;span style="color: #000000;"&gt; Execute()
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Parse the language neutral resource files&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;      _processed &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; ParseResxFiles(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;);                    
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Identify which entries contain duplicates (i.e. &amp;gt; 1 entry for the same key)&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;      _duplicates &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; _processed.Values.Where(x &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; x.Count &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;);    
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt; &lt;span style="color: #000000;"&gt;      
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Identify which duplicates contain the same value across all files&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;      _distinct &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; _duplicates.Where(x &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; x.IsDistinct());         
&lt;/span&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt; &lt;span style="color: #000000;"&gt;      
&lt;/span&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Identify which duplicates contain different values across all files&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;      _notDistinct &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; _duplicates.Where(x &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #000000;"&gt;!&lt;/span&gt;&lt;span style="color: #000000;"&gt;x.IsDistinct());     &lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;p&gt;Once we have the lists, we can setup the stats for the scan as follow:&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:b1b368b4-0652-4c72-a120-654689c42e93" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 622px; height: 119px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Setup the stats&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;2&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;    _stats &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXStatsSummary
&lt;/span&gt;&lt;span style="color: #008080;"&gt;3&lt;/span&gt; &lt;span style="color: #000000;"&gt;     {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;4&lt;/span&gt; &lt;span style="color: #000000;"&gt;         Scanned &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; _processed.Values.Sum(x &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; x.Count),
&lt;/span&gt;&lt;span style="color: #008080;"&gt;5&lt;/span&gt; &lt;span style="color: #000000;"&gt;         Duplicates &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; _duplicates.Sum(x &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; x.Count),
&lt;/span&gt;&lt;span style="color: #008080;"&gt;6&lt;/span&gt; &lt;span style="color: #000000;"&gt;         DuplicatesTagged &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; _duplicates.Sum(x &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; x.EntriesTaggedCount()) 
&lt;/span&gt;&lt;span style="color: #008080;"&gt;7&lt;/span&gt; &lt;span style="color: #000000;"&gt;     };&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Lastly, we finish off the scan by creating two separate dictionaries of all resource nodes keyed per file from the existing &lt;em&gt;_distinct&lt;/em&gt; and &lt;em&gt;_notDistinct&lt;/em&gt; filtered.&amp;nbsp; This is useful for reporting which files contained duplicates and will be used extensively in the next blog post where we cover how to actually eliminate the resource duplication.&amp;nbsp; &lt;/p&gt;
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:d4a9deae-fdb5-4476-92b3-03e398049e88" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 686px; height: 62px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Setup Dictionaries keyed per file for the respective duplicate resources&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;2&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;      _distinctFileDuplicates &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; BuildResxFileList(_distinct, x &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; x.ToDictionary());
&lt;/span&gt;&lt;span style="color: #008080;"&gt;3&lt;/span&gt; &lt;span style="color: #000000;"&gt;      _mostUsedFileDuplicates &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; BuildResxFileList(_notDistinct, x &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; x.FindMostUsedEntries().ToDictionary(y &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; y.File, y &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; y.Node));&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Here is the BuildResxFileList routine:&lt;/p&gt;
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:a3754cb6-b481-47e5-8833-a97d0f4d9819" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 686px; height: 262px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;protected&lt;/span&gt;&lt;span style="color: #000000;"&gt; Dictionary&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;, List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDataNode&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; BuildResxFileList(IEnumerable&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDuplicate&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; duplicates, Func&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDuplicate, Dictionary&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;, ResXDataNode&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; findEntriesFilter)
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;span style="color: #000000;"&gt;    {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;span style="color: #000000;"&gt;        Dictionary&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;, List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDataNode&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; resourceFiles &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; Dictionary&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;, List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDataNode&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;();
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;foreach&lt;/span&gt;&lt;span style="color: #000000;"&gt; (var duplicate &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;in&lt;/span&gt;&lt;span style="color: #000000;"&gt; duplicates)
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;span style="color: #000000;"&gt;        {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #000000;"&gt;            Dictionary&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;, ResXDataNode&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; entries &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; findEntriesFilter(duplicate);
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; &lt;span style="color: #000000;"&gt;            &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;foreach&lt;/span&gt;&lt;span style="color: #000000;"&gt; (var entry &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;in&lt;/span&gt;&lt;span style="color: #000000;"&gt; entries)
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt; &lt;span style="color: #000000;"&gt;            {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt; &lt;span style="color: #000000;"&gt;                &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (&lt;/span&gt;&lt;span style="color: #000000;"&gt;!&lt;/span&gt;&lt;span style="color: #000000;"&gt;resourceFiles.ContainsKey(entry.Key))
&lt;/span&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;                    resourceFiles.Add(entry.Key, &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDataNode&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;());
&lt;/span&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt; &lt;span style="color: #000000;"&gt;                resourceFiles[entry.Key].Add(entry.Value);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt; &lt;span style="color: #000000;"&gt;            }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;14&lt;/span&gt; &lt;span style="color: #000000;"&gt;        }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;15&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; resourceFiles;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;16&lt;/span&gt; &lt;span style="color: #000000;"&gt;    }&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;With all of this infrastructure in place in the ResxTaskBase, creating the &lt;strong&gt;ResXFindDuplicate&lt;/strong&gt; task is straightforward as illustrated below.&lt;/p&gt;
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:d9b81dce-e88f-44f6-958a-bd7a930a70f4" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 686px; height: 1261px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; ResXFindDuplicates : ResXTaskBase
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;span style="color: #000000;"&gt;    {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;enum&lt;/span&gt;&lt;span style="color: #000000;"&gt; LogOutput
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #000000;"&gt;        {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;span style="color: #000000;"&gt;            Text &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;,
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #000000;"&gt;            Xml &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;1&lt;/span&gt;&lt;span style="color: #000000;"&gt;,
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; &lt;span style="color: #000000;"&gt;            Csv &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;2&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt; &lt;span style="color: #000000;"&gt;        }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#region&lt;/span&gt;&lt;span style="color: #000000;"&gt; Properties&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt; &lt;span style="color: #000000;"&gt;        [Output]
&lt;/span&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; ITaskItem[] FilesWithDuplicates { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt;; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt;; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;14&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;15&lt;/span&gt; &lt;span style="color: #000000;"&gt;        [Output]
&lt;/span&gt;&lt;span style="color: #008080;"&gt;16&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; ITaskItem[] FilesWithNoDuplicates { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt;; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt;; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;17&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;18&lt;/span&gt; &lt;span style="color: #000000;"&gt;        [Required]
&lt;/span&gt;&lt;span style="color: #008080;"&gt;19&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; LogFile { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt;; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt;; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;20&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;21&lt;/span&gt; &lt;span style="color: #000000;"&gt;        [Required]
&lt;/span&gt;&lt;span style="color: #008080;"&gt;22&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; LogType { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt;; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt;; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;23&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;24&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#endregion&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;25&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;26&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#region&lt;/span&gt;&lt;span style="color: #000000;"&gt; Methods&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;27&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;28&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;override&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;bool&lt;/span&gt;&lt;span style="color: #000000;"&gt; Execute()
&lt;/span&gt;&lt;span style="color: #008080;"&gt;29&lt;/span&gt; &lt;span style="color: #000000;"&gt;        {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;30&lt;/span&gt; &lt;span style="color: #000000;"&gt;            Log.LogMessage(MessageImportance.Normal, &lt;/span&gt;&lt;span style="color: #800000;"&gt;@&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Finding duplicate resources within {0} resx files...&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, SourceFiles.Length);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;31&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;32&lt;/span&gt; &lt;span style="color: #000000;"&gt;            &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Parse the language neutral resources&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;33&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;            &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;bool&lt;/span&gt;&lt;span style="color: #000000;"&gt; result &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;base&lt;/span&gt;&lt;span style="color: #000000;"&gt;.Execute();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;34&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;35&lt;/span&gt; &lt;span style="color: #000000;"&gt;            Log.LogMessage(MessageImportance.High, _stats.ToString());
&lt;/span&gt;&lt;span style="color: #008080;"&gt;36&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;37&lt;/span&gt; &lt;span style="color: #000000;"&gt;            &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Create the output parameters containing the files affected/not affected&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;38&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;            List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ITaskItem&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; duplicates &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ITaskItem&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;39&lt;/span&gt; &lt;span style="color: #000000;"&gt;            List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ITaskItem&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; noDuplicates &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ITaskItem&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;40&lt;/span&gt; &lt;span style="color: #000000;"&gt;            &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;foreach&lt;/span&gt;&lt;span style="color: #000000;"&gt; (ITaskItem sourceResxFile &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;in&lt;/span&gt;&lt;span style="color: #000000;"&gt; SourceFiles)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;41&lt;/span&gt; &lt;span style="color: #000000;"&gt;            {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;42&lt;/span&gt; &lt;span style="color: #000000;"&gt;                &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (_distinctFileDuplicates.ContainsKey(sourceResxFile.ItemSpec))
&lt;/span&gt;&lt;span style="color: #008080;"&gt;43&lt;/span&gt; &lt;span style="color: #000000;"&gt;                    duplicates.Add(sourceResxFile);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;44&lt;/span&gt; &lt;span style="color: #000000;"&gt;                &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;else&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;45&lt;/span&gt; &lt;span style="color: #000000;"&gt;                    noDuplicates.Add(sourceResxFile);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;46&lt;/span&gt; &lt;span style="color: #000000;"&gt;            }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;47&lt;/span&gt; &lt;span style="color: #000000;"&gt;            FilesWithDuplicates &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; duplicates.ToArray();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;48&lt;/span&gt; &lt;span style="color: #000000;"&gt;            FilesWithNoDuplicates &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; noDuplicates.ToArray();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;49&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;50&lt;/span&gt; &lt;span style="color: #000000;"&gt;            &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Create the Log file&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;51&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;            &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (Enum.IsDefined(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;typeof&lt;/span&gt;&lt;span style="color: #000000;"&gt; (LogOutput), LogType))
&lt;/span&gt;&lt;span style="color: #008080;"&gt;52&lt;/span&gt; &lt;span style="color: #000000;"&gt;            {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;53&lt;/span&gt; &lt;span style="color: #000000;"&gt;                Log.LogMessage(MessageImportance.Normal, &lt;/span&gt;&lt;span style="color: #800000;"&gt;@&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Writing {0} log to {1}...&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, Enum.GetName(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;typeof&lt;/span&gt;&lt;span style="color: #000000;"&gt; (LogOutput), LogType), LogFile);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;54&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;55&lt;/span&gt; &lt;span style="color: #000000;"&gt;                &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; ((LogOutput) LogType &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; LogOutput.Text)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;56&lt;/span&gt; &lt;span style="color: #000000;"&gt;                    WriteTextLog(_stats, _duplicates);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;57&lt;/span&gt; &lt;span style="color: #000000;"&gt;                &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;else&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; ((LogOutput) LogType &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; LogOutput.Xml)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;58&lt;/span&gt; &lt;span style="color: #000000;"&gt;                    WriteXmlLog(_stats, _duplicates);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;59&lt;/span&gt; &lt;span style="color: #000000;"&gt;                &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;else&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; ((LogOutput) LogType &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; LogOutput.Csv)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;60&lt;/span&gt; &lt;span style="color: #000000;"&gt;                    WriteCsvLog(_duplicates);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;61&lt;/span&gt; &lt;span style="color: #000000;"&gt;            }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;62&lt;/span&gt; &lt;span style="color: #000000;"&gt;            &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;else&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;63&lt;/span&gt; &lt;span style="color: #000000;"&gt;            {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;64&lt;/span&gt; &lt;span style="color: #000000;"&gt;                Log.LogError(&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Invalid LogType specified&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;65&lt;/span&gt; &lt;span style="color: #000000;"&gt;                result &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;false&lt;/span&gt;&lt;span style="color: #000000;"&gt;;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;66&lt;/span&gt; &lt;span style="color: #000000;"&gt;            }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;67&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;68&lt;/span&gt; &lt;span style="color: #000000;"&gt;            &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; result;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;69&lt;/span&gt; &lt;span style="color: #000000;"&gt;        }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;70&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;71&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; WriteCsvLog(IEnumerable&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;ResXDuplicate&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; duplicates)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;72&lt;/span&gt; &lt;span style="color: #000000;"&gt;        {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;73&lt;/span&gt; &lt;span style="color: #000000;"&gt;            StringBuilder sb &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; StringBuilder();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;74&lt;/span&gt; &lt;span style="color: #000000;"&gt;            sb.AppendLine(&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Shared,File,Name,Value&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;75&lt;/span&gt; &lt;span style="color: #000000;"&gt;            &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;foreach&lt;/span&gt;&lt;span style="color: #000000;"&gt; (var entry &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;in&lt;/span&gt;&lt;span style="color: #000000;"&gt; duplicates.OrderByDescending(x &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; x.Count))
&lt;/span&gt;&lt;span style="color: #008080;"&gt;76&lt;/span&gt; &lt;span style="color: #000000;"&gt;            {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;77&lt;/span&gt; &lt;span style="color: #000000;"&gt;                sb.AppendFormat(entry.ToCsvText());
&lt;/span&gt;&lt;span style="color: #008080;"&gt;78&lt;/span&gt; &lt;span style="color: #000000;"&gt;            }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;79&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;80&lt;/span&gt; &lt;span style="color: #000000;"&gt;            WriteLogFile(sb, LogFile);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;81&lt;/span&gt; &lt;span style="color: #000000;"&gt;        }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;82&lt;/span&gt; &lt;span style="color: #000000;"&gt;        
&lt;/span&gt;&lt;span style="color: #008080;"&gt;83&lt;/span&gt; &lt;span style="color: #000000;"&gt;        ...&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;We receive the &lt;em&gt;LogFile&lt;/em&gt; and &lt;em&gt;LogType&lt;/em&gt; as input parameters to the MSBuild task and we have separate &lt;em&gt;FilesWithDuplicates&lt;/em&gt; and &lt;em&gt;FilesWithNoDuplicates&lt;/em&gt; output parameters that will contain the names of the files with duplicates and without duplicates.&amp;nbsp; After calling into the base class (line 33) to scan the files and setup all the data structures, we simply setup the list of output files (lines 40-48) and also create the desired log output (lines 51-66).&lt;/p&gt;
&lt;h2&gt;Invoking the MSBuild Task&lt;/h2&gt;
&lt;p&gt;Now that we’ve covered the MSBuild task, let’s see how we would invoke this when compiling our projects within Visual Studio.&amp;nbsp; As every .csproj in Visual Studio is a MSBuild file, invoking the task is actually quite easy.&amp;nbsp; We will hook into the BeforeBuild target of the project containing our resource files to execute our ResXFindDuplicate task.&amp;nbsp;&amp;nbsp; We therefore edit the specific .csproj and start by adding the following to identify the set of resource files to scan:&lt;/p&gt;
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:6d46770f-0960-4d9a-a1c5-3cab09bf06f5" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 686px; height: 243px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;PropertyGroup&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;ResxDuplicatesFile&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Resources\SharedResources.resx&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;ResxDuplicatesFile&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;ResxFindDuplicatesLog&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;Resources\SharedResources.csv&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;ResxFindDuplicatesLog&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;NEW_LINE&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;%0D%0A&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;NEW_LINE&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;TAB&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;%09&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;TAB&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;PropertyGroup&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;ItemGroup&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;ResxInputs &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;Include&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;Resources\*.resx&amp;quot;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; Exclude&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;Resources\*.*.resx&amp;quot;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Visible&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;false&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;Visible&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;ResxInputs&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;ResxOutputs &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;Include&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;$(ResxFindDuplicatesLog)&amp;quot;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Visible&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;false&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;Visible&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;ResxOutputs&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;14&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;ItemGroup&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;15&lt;/span&gt; &lt;span style="color: #000000;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Notice that the &lt;em&gt;ResxInputs&lt;/em&gt; ItemGroup (lines 8-10) is set to match only the resource neutral resource files by excluding any culture specific files.&amp;nbsp; Also notice that we set the visibility of these item groups to false to prevent them from showing up in the Visual Studio solution explorer.&amp;nbsp; We can now invoke our custom task by hooking it into the &lt;em&gt;BeforeBuild&lt;/em&gt; target.&amp;nbsp; Every .csproj has a &lt;em&gt;BeforeBuild&lt;/em&gt; and &lt;em&gt;AfterBuild&lt;/em&gt; target that Visual Studio will invoke before and after every time it compiles the project.&lt;/p&gt;
&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:daa1d34d-1e3f-4066-b852-79e343ab2a5e" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 686px; height: 184px;background-color:White;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: visible;;font-family:Consolas;font-size:11.25"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Import &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;Project&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;..\..\Tools\MSBuild\Pragma.MSBuild.Tasks\Pragma.MSBuild.Tasks.Targets&amp;quot;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;/&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Target &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;Name&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;BeforeBuild&amp;quot;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; Inputs&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;@(ResxInputs)&amp;quot;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; Outputs&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;@(ResxOutputs)&amp;quot;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #008000;"&gt;&amp;lt;!--&lt;/span&gt;&lt;span style="color: #008000;"&gt; Find the resx files containing duplicates &lt;/span&gt;&lt;span style="color: #008000;"&gt;--&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;ResXFindDuplicates &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;SourceFiles&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;@(ResxInputs)&amp;quot;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; LogType&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;2&amp;quot;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; LogFile&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;$(ResxFindDuplicatesLog)&amp;quot;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Output &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;TaskParameter&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;FilesWithDuplicates&amp;quot;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; ItemName&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;ResxFilesWithDuplicates&amp;quot;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;/&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Output &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;TaskParameter&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;FilesWithNoDuplicates&amp;quot;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; ItemName&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;ResxFilesWithNoDuplicates&amp;quot;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;/&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;ResXFindDuplicates&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Message &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;Text&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;Resx files with duplicates:$(NEW_LINE)$(TAB)@(ResxFilesWithDuplicates-&amp;gt;'%(RecursiveDir)%(FileName)%(Extension)', '$(NEW_LINE)$(TAB)')&amp;quot;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; Importance&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;normal&amp;quot;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;/&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Message &lt;/span&gt;&lt;span style="color: #FF0000;"&gt;Text&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;Resx files with no duplicates:$(NEW_LINE)$(TAB)@(ResxFilesWithNoDuplicates-&amp;gt;'%(RecursiveDir)%(FileName)%(Extension)', '$(NEW_LINE)$(TAB)')&amp;quot;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; Importance&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;=&amp;quot;normal&amp;quot;&lt;/span&gt;&lt;span style="color: #FF0000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;/&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000;"&gt;Target&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;After importing our compiled MSBuild tasks, we simply invoke it as showed on lines 4-7 by specifying what kind of log file we want (2 = CSV) and also where the log should be created.&amp;nbsp; We can investigate and mine the log output to further assist us with out translation efforts.&amp;nbsp;&amp;nbsp; Finally, here is the output that we will now receive in Visual Studio every time we compile the project containing our resource files:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="CompileOutput" border="0" alt="CompileOutput" src="http://lh6.ggpht.com/-mhlbjXYBnek/TfruGsqhjtI/AAAAAAAAAu8/n-p6qA421E0/CompileOutput%25255B2%25255D.png?imgmax=800" width="640" height="143"&gt; &lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Now that we know the amount of resource duplication we have across our resource files, we need a mechanism to try and eliminate as much of the duplication as possible.&amp;nbsp; This we’ll cover in the next post of &lt;a href="http://fromthedevtrenches.blogspot.com/2011/04/managing-net-resx-duplication-part-1.html" target="_blank"&gt;the series&lt;/a&gt;. Till then… &lt;img alt="Smile" src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/regular_smile.gif"&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-4070416158032874451?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/b3xK3ZS35YA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/4070416158032874451/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2011/06/managing-net-resx-duplication-part-2.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/4070416158032874451?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/4070416158032874451?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/b3xK3ZS35YA/managing-net-resx-duplication-part-2.html" title="Managing .NET RESX Duplication – Part 2: Identifying Resource Duplication" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/-hVH66EFKOfo/TfrtuDY8nEI/AAAAAAAAAu0/TWS_MfI275g/s72-c/Globe4.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2011/06/managing-net-resx-duplication-part-2.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkANSH85eCp7ImA9WhZQEEg.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-6258636703063612357</id><published>2011-04-17T16:33:00.001+02:00</published><updated>2011-04-17T16:33:19.120+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-17T16:33:19.120+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Localization" /><category scheme="http://www.blogger.com/atom/ns#" term="DotNET" /><title>Managing .NET RESX Duplication - Part 1: Solution Requirements and Design</title><content type="html">&lt;p&gt;&lt;img style="border-right-width: 0px; margin: 0px 20px 0px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Globe" border="0" alt="Globe" align="left" src="http://lh4.ggpht.com/_ziqU4IJY4Uc/Tar6LUYcjLI/AAAAAAAAAuw/Ex-9-TepSF8/Globe4.jpg?imgmax=800" width="121" height="123" /&gt; &lt;a href="http://fromthedevtrenches.blogspot.com/2011/04/pragma-on-key-silverlight-localization.html" target="_blank"&gt;Last time around&lt;/a&gt; I blogged a bit about the work that we are doing to add multi-language support to On Key v5.4, &lt;a href="http://www.pragmaworld.net/" target="_blank"&gt;Pragma’s&lt;/a&gt; Enterprise Asset Management System (EAMS).&amp;#160; As mentioned, we have 250+ resources files containing around 8000+ resource entries that need to be translated.&amp;#160; After some further investigation, it turns out that we have close to 49% duplication across the resources files being used by our screens.&amp;#160; This high level of duplication is mostly due to these files being code generated. So during the last week we’ve spend some time looking at various options for minimizing and managing the duplication and thus the amount of strings that we need to pass onto Translators to get translated.&amp;#160; &lt;/p&gt;  &lt;p&gt;I’m going to cover the solution we are thinking of using in a series of 3 blog posts.&amp;#160; Here is a high level overview of the posts:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Solution Requirements and Design &lt;/li&gt;    &lt;li&gt;Code: Identifying resource duplication &lt;/li&gt;    &lt;li&gt;Code: Managing resource duplication &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Let’s start by looking at our high level requirements for the solution.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt;  &lt;h2&gt;Requirements&lt;/h2&gt;  &lt;p&gt;On a high level we identified the following requirements to guide us in creating a solution:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Continuously Execute - The solution must be continuously executed and not only once off as we will be adding more resources over time.&amp;#160; &lt;/li&gt;    &lt;li&gt;Minimize/Eliminate Rework - Minimize/eliminate rework on all the existing screens &lt;/li&gt;    &lt;li&gt;Minimize/Eliminate Duplication – Minimize/eliminate the duplication in the resource files &lt;/li&gt;    &lt;li&gt;Streamline Translation Effort – Prevent Translators from wasting time on translation duplicates more than once &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;I think it is important to note that we were looking for a solution that in our opinion strikes the best balance between all of these requirements.&amp;#160; Take for example Requirements 2 and 3.&amp;#160; Solving Requirement 3 in the best possible way may impact negatively on Requirement 2.&amp;#160; &lt;/p&gt;  &lt;h2&gt;SOLUTION&lt;/h2&gt;  &lt;p&gt;We broke our solution up into two distinct phases.&amp;#160;&amp;#160; Both phases have been implemented as &lt;a href="http://msdn.microsoft.com/en-us/library/t9883dzc.aspx" target="_blank"&gt;custom MSBuild tasks&lt;/a&gt; to allow it to run as part of the build process and thus satisfy the &lt;em&gt;Continuously Execute&lt;/em&gt; requirement.&amp;#160; In Phase One we &lt;strong&gt;identify&lt;/strong&gt; the resources that are duplicated across all of the .RESX resource files.&amp;#160; This is done continuously on every compilation of the source code in Visual Studio.&amp;#160; The overhead is small - 3 seconds on my 3 year old laptop.&amp;#160;&amp;#160; The output of this phase is a report in either CSV/Xml format and a list of .RESX files containing duplicates.&amp;#160; The data in the report can be mined by both the Development Team and Translators.&amp;#160;&amp;#160; The Development Team can identify areas of duplication that we need to address, inconsistencies in translations being applied across screens and much more.&amp;#160; The Translators can use it to make sure they don’t translate values more than once and also for other general query purposes (e.g. what screens are using a value etc.)&lt;/p&gt;  &lt;p&gt;The list of .RESX file containing the duplicates can then be fed into Phase Two that attempts to &lt;strong&gt;minimize&lt;/strong&gt; the duplication.&amp;#160; It works by copying the duplicates into a single, separate &lt;b&gt;&lt;i&gt;shared&lt;/i&gt;&lt;/b&gt; resource file.&amp;#160; The idea being that instead of translating every duplicate, we only translate the entries in the shared resource file and re-use them across all the screens were they apply.&amp;#160;&amp;#160; This cuts down on about half of the duplicated strings for our screens.&amp;#160; To make use of the shared resources, we created a custom Resource Manager to always first query the shared resource file when it looks for a resource.&amp;#160; If the resource is found in the shared file, it is used from there and not from the screen specific file.&amp;#160; We can therefore ignore the duplicate entries in the screen specific files and not translate them as they are automatically overridden by their counterparts from the shared resource file.&amp;#160;&amp;#160; This satisfies the &lt;em&gt;Minimize/Eliminate Duplication&lt;/em&gt; requirement.&amp;#160; We investigated the possibility of actually deleting these entries from the screen specific resource files, but this caused issues from a binding perspective in our XAML screens.&amp;#160; So to satisfy the &lt;em&gt;Minimize/Eliminate Rework&lt;/em&gt; requirement we decided to leave them intact.&amp;#160;&amp;#160; We do however update the comment in the resource files to indicate that an entry is being shared (using &lt;b&gt;[## SHARED ##]&lt;/b&gt; tag).&amp;#160; &lt;/p&gt;  &lt;p&gt;The down side is that we are obviously still carry these strings around in all our language neutral resource files and thus in a translation solution like Amanuens.&amp;#160; The Translators should however never have to translate the duplicate shared resource entries if they use the CSV report or look at the comment tags.&amp;#160; This then satisfies our &lt;em&gt;Streamline Translation Effort&lt;/em&gt; requirement.&lt;/p&gt;  &lt;p&gt;As mentioned, the first phase is continuously executed as part of compiling our source code and requires no manual intervention.&amp;#160; Phase 2 can also be executed as part of compiling the solution, but it does require you to first check out the shared .RESX file from TFS and setting a MSBuild variable so that the MSBuild task will execute.&amp;#160; More on this later. &lt;/p&gt;  &lt;h2&gt;Stats&lt;/h2&gt;  &lt;p&gt;Here is a rundown of the stats generated after execution Phase 1 and 2 on all our existing screen resource files.&amp;#160; We specifically only used the screen resources files as they account for the majority of duplication in our system.&lt;/p&gt;  &lt;h5&gt;Phase 1&lt;/h5&gt;  &lt;ul&gt;   &lt;li&gt;Files Scanned: 270 &lt;/li&gt;    &lt;li&gt;Files With Duplicates: 263 &lt;/li&gt;    &lt;li&gt;File With No Duplicates: 7 &lt;/li&gt;    &lt;li&gt;Resources Read: 6458 &lt;/li&gt;    &lt;li&gt;Duplicate Resources Identified: 5025 resources &lt;/li&gt;    &lt;li&gt;Duplicate Resources that can shared: 2514 resources identified by 428 keys &lt;/li&gt;    &lt;li&gt;Duplicate Resources that cannot be shared: 2511 resources identified by 197 keys &lt;/li&gt; &lt;/ul&gt;  &lt;h5&gt;Phase 2&lt;/h5&gt;  &lt;ul&gt;   &lt;li&gt;Files Scanned: 263 &lt;/li&gt;    &lt;li&gt;Resources extracted to shared file: 2514 resources identified by 428 keys &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;An area of current concern for us is that we will have to go through a cleanup exercise on our own resource files before getting the Translators cracking.&amp;#160; This is illustrated by the 2511 duplicate resources that we cannot currently extract as shared resources.&amp;#160; To illustrate our problem let’s take the &lt;i&gt;‘Id’&lt;/i&gt; key as an example.&amp;#160;&amp;#160; After mining the key using the CSV report, we discovered that we have 247 duplicate entries for the &lt;em&gt;‘Id’&lt;/em&gt; key.&amp;#160; Of these 247 duplicates, 242 use the same value &lt;i&gt;‘Id’&lt;/i&gt; .&amp;#160; The remaining 5 entries use the value &lt;i&gt;‘Parent Id’&lt;/i&gt;.&amp;#160; Because of these differences we cannot safely extract ‘&lt;i&gt;Id’&lt;/i&gt; as a shared resource.&amp;#160; The differences for these 5 specific screens may be valid based on the screen context.&amp;#160; The differences may however also be invalid due to spelling mistakes, incorrect specs or even a wrong implementation from the developer.&amp;#160; The Translator will however now be wasting time translating this over and over again &lt;img alt="Sad" src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/sad_smile.gif" /&gt;&amp;#160; &lt;/p&gt;  &lt;p&gt;We therefore think it is prudent for us to first spend a bit of time going through our resources files to see what we can fix.&amp;#160; The spelling mistakes and other errors should be easy to fix.&amp;#160; The contextual differences will be more complex and will require looking at the specific screen to determine its validity.&amp;#160; For scenarios like the &lt;em&gt;‘Id’&lt;/em&gt; key above I think we should rather create a separate &lt;em&gt;‘ParentId’&lt;/em&gt; key and update the 5 screens to use the &lt;em&gt;‘ParentId’&lt;/em&gt; instead of &lt;em&gt;‘Id’&lt;/em&gt; as a resource.&amp;#160; This violates the &lt;em&gt;Minimize/Eliminate Rework&lt;/em&gt; requirement but it does improve the &lt;em&gt;Minimize/Eliminate Duplication&lt;/em&gt; and &lt;em&gt;Streamline Translation Effort&lt;/em&gt; requirements.&lt;/p&gt;  &lt;h2&gt;Summary&lt;/h2&gt;  &lt;p&gt;In the next post I will look at some of the code for the MSBuild task that identifies the duplication across the resources files.&amp;#160; Stay tuned!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-6258636703063612357?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/itksa5iSM4g" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/6258636703063612357/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2011/04/managing-net-resx-duplication-part-1.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6258636703063612357?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6258636703063612357?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/itksa5iSM4g/managing-net-resx-duplication-part-1.html" title="Managing .NET RESX Duplication - Part 1: Solution Requirements and Design" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_ziqU4IJY4Uc/Tar6LUYcjLI/AAAAAAAAAuw/Ex-9-TepSF8/s72-c/Globe4.jpg?imgmax=800" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2011/04/managing-net-resx-duplication-part-1.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEUAQHk_cCp7ImA9WhZRFU0.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-8559195073451864154</id><published>2011-04-11T09:07:00.001+02:00</published><updated>2011-04-11T09:17:21.748+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-11T09:17:21.748+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Localization" /><category scheme="http://www.blogger.com/atom/ns#" term="OnKey" /><category scheme="http://www.blogger.com/atom/ns#" term="DotNET" /><category scheme="http://www.blogger.com/atom/ns#" term="Silverlight" /><title>Pragma On Key Silverlight Localization</title><content type="html">&lt;p&gt;&lt;img style="border-right-width: 0px; margin: 0px 50px 0px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Globe" border="0" alt="Globe" align="left" src="http://lh3.ggpht.com/_ziqU4IJY4Uc/TaKor0Gtu8I/AAAAAAAAAuo/BQU6021TPUk/Globe%5B5%5D.jpg?imgmax=800" width="153" height="155" /&gt; &lt;/p&gt;  &lt;p&gt;One of the big features that we are adding to Version 5.4 of On Key, &lt;a href="http://www.pragmaworld.net/" target="_blank"&gt;Pragma’s&lt;/a&gt; Enterprise Asset Management System, is the ability to use the system in different languages.&amp;#160; It seems like the first language we will support in addition to English will be Brazilian Portuguese&amp;#160; to support customers for our &lt;a href="http://www.pragmabrasil.com.br/" target="_blank"&gt;Pragma Brazil&lt;/a&gt; service company.&amp;#160; So I’ve been spending some time during the past week or two looking at the various aspects of On Key that we need to localize to determine the best solutions for getting everything localized.&amp;#160; In this post I will cover some useful information I discovered in my research.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt;  &lt;h2&gt;Static Text&lt;/h2&gt;  &lt;p&gt;Fortunately we’ve been following the &lt;a href="http://msdn.microsoft.com/en-us/library/cc838238(v=vs.95).aspx" target="_blank"&gt;recommended best practice for localizing Silverlight applications&lt;/a&gt; by storing all the text that needs to be localized in external resource files.&amp;#160; We currently have around 290 resources files with around 8200 strings that need to be translated from English into other languages.&amp;#160; The resources stored within these files are all static type resources like menu text, captions, tooltips, error messages etc.&amp;#160; I was looking for a solution that would make the process of managing and translating these strings as easy as possible.&lt;/p&gt;  &lt;p&gt;I’ve been keeping an eye on &lt;a href="http://amanuens.com/" target="_blank"&gt;Amanuens&lt;/a&gt; since I first read about their localization solution back in 2010, so I headed off to their &lt;a href="http://amanuens.com/" target="_blank"&gt;web-site&lt;/a&gt; to see how it has matured since the early beta phases.&amp;#160; Amanuens gives you the ability to upload your resource files into the cloud to get translators to translate them into your language of choice.&amp;#160; You can assign your own people as translators or even get a quote from an external organization to translate your resources into your language of choice.&amp;#160; This is all done via an easy-to-use web-based interface.&amp;#160; The output is the actual translated resource files in a variety of formats of which .NET resource files is one.&amp;#160; Amanuens also has some other really nifty features like a shared &lt;a href="http://support.amanuens.com/TranslationMemory.ashx" target="_blank"&gt;Translation Memory&lt;/a&gt;, the ability &lt;a href="http://support.amanuens.com/Screenshots.ashx" target="_blank"&gt;to attach screenshots&lt;/a&gt; to provide context for translations and &lt;a href="http://amanuens.com/Tour.aspx" target="_blank"&gt;much more&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;After creating a public facing Subversion repository containing our resource files, I signed up for a trial to experience the work flow involved in getting some of our resource files translated.&amp;#160; I was quite happy with the usability of the system and it seems to be a great solution for translating our resources into multiple languages over a period of time.&amp;#160; The change tracking capabilities of automatically picking up new strings or changes to existing strings to notify translators of work to be done is a really powerful feature and one that will really simplify the management of the resource files over time.&amp;#160; &lt;/p&gt;  &lt;h2&gt;Dynamic Text&lt;/h2&gt;  &lt;p&gt;In addition to the static text, On Key also has a nifty feature called Phrase Translations.&amp;#160; A phrase is defined as a piece of text delimited by the “&lt;strong&gt;{&lt;/strong&gt;“ and “&lt;strong&gt;}&lt;/strong&gt;” brackets. Any customer can create translations for their own phrases via the On Key UI to allow the engineers, artisans and other people using On Key to view certain terminology (like technical terms) in their language of preference. Take for example the phrase &lt;strong&gt;&lt;em&gt;{Check} the {Bearing} &lt;/em&gt;&lt;/strong&gt;as the description of a maintenance task to be executed. When an artisan views the description, the text will automatically be translated into their language preference specified at logon, i.e. &lt;strong&gt;&lt;em&gt;Inspekteer the Draer&lt;/em&gt;&lt;/strong&gt; if they specified Afrikaans. The technical implementation for these Phrase Translations is actually quite interesting as we utilize the &lt;a href="http://www.sqlclr.net/" target="_blank"&gt;SQLCLR&lt;/a&gt; to get the best performance possible, but that is a post for another day.&lt;/p&gt;  &lt;h2&gt;Dynamically loading Resources&lt;/h2&gt;  &lt;p&gt;One of the problems with Silverlight localization is that all the resources for the different languages are packaged into the single XAP file that is downloaded to the clients.&amp;#160; Ideally we only want to download the resources for each client’s neutral and language specific cultures.&amp;#160; One &lt;a href="http://msdn.microsoft.com/en-us/library/cc838238%28v=vs.95%29.aspx#Deploy" target="_blank"&gt;solution to the problem&lt;/a&gt; is to create culture specific XAP files for every language supported.&amp;#160; When the initial request for the application hits your server, you inspect the client’s culture settings passed via the ASP.NET request and redirect the client to load the relevant culture specific XAP file.&amp;#160; I wasn’t keen on creating separate build configurations for all the future languages that we will support and did some further research into the issue.&amp;#160; I then came across &lt;a href="http://www.guysmithferrier.com/post/2010/11/Video-Internationalizing-Silverlight-at-SLUGUK.aspx" target="_blank"&gt;this excellent video presentation&lt;/a&gt; by Guy Smith-Ferrier on Internationalizing Silverlight applications.&amp;#160; In the presentation he covers a technique whereby he &lt;a href="http://www.guysmithferrier.com/post/2010/10/Building-Localized-XAP-Resource-Files-For-Silverlight-4.aspx" target="_blank"&gt;creates separate XAP files using a MSBuild task&lt;/a&gt; that contains only the localized resources and not the complete application.&amp;#160; All of this happens &lt;strong&gt;without&lt;/strong&gt; having to create separate build configurations in Visual Studio.&amp;#160; He then further illustrates how to use &lt;a href="http://mef.codeplex.com/" target="_blank"&gt;MEF&lt;/a&gt; to dynamically download the correct culture specific XAP file at run-time when the Silverlight application starts.&amp;#160; &lt;/p&gt;  &lt;p&gt;This was more to my liking and after spending some time looking at the source code, I implemented something similar in our environment.&amp;#160; A problem that Guy does not address in his solution is the loading of the culture neutral resources, i.e. it only loads the culture specific resources.&amp;#160; As every &lt;a href="http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.aspx" target="_blank"&gt;CultureInfo&lt;/a&gt; instance has a reference to its &lt;a href="http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.parent.aspx" target="_blank"&gt;Parent&lt;/a&gt; culture, I set about to create a solution whereby I traverse the culture tree upwards, trying to download a XAP file for every culture neutral Parent resource until I arrived at the Invariant Culture that is compiled into the original application XAP file.&amp;#160; Here is some sample C# code that illustrates how to accomplish this:&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:a8b210e4-69c1-4fe3-bb33-3e90da8edc5c" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 686px; height: 543px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; App()
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;span style="color: #000000;"&gt;    Startup &lt;/span&gt;&lt;span style="color: #000000;"&gt;+=&lt;/span&gt;&lt;span style="color: #000000;"&gt; Application_Startup;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #000000;"&gt;    Exit &lt;/span&gt;&lt;span style="color: #000000;"&gt;+=&lt;/span&gt;&lt;span style="color: #000000;"&gt; Application_Exit;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;span style="color: #000000;"&gt;    UnhandledException &lt;/span&gt;&lt;span style="color: #000000;"&gt;+=&lt;/span&gt;&lt;span style="color: #000000;"&gt; Application_UnhandledException;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; &lt;span style="color: #000000;"&gt;    InitializeComponent();
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; Application_Startup(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;object&lt;/span&gt;&lt;span style="color: #000000;"&gt; sender, StartupEventArgs e)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt; &lt;span style="color: #000000;"&gt;    var options &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; NinjectSettings {InjectAttribute &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;typeof&lt;/span&gt;&lt;span style="color: #000000;"&gt; (InjectAttribute)};
&lt;/span&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt; &lt;span style="color: #000000;"&gt;    IocContainer.Kernel &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; StandardKernel(options, &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; IocInfrastructureModule(), &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; IocNavigationModule(), &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; IocServiceModule());
&lt;/span&gt;&lt;span style="color: #008080;"&gt;14&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;15&lt;/span&gt; &lt;span style="color: #000000;"&gt;    DownloadLanguageResources(Thread.CurrentThread.CurrentUICulture);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;16&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;17&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;18&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; DownloadLanguageResources(CultureInfo culture)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;19&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;20&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; xapResourceFilename &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; String.Format(CultureInfo.InvariantCulture, &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;{0}.{1}.xap&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Pragma.OnKey5.Client&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, culture.Name);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;21&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;22&lt;/span&gt; &lt;span style="color: #000000;"&gt;    XapLoader xapLoader &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; XapLoader(xapResourceFilename);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;23&lt;/span&gt; &lt;span style="color: #000000;"&gt;    xapLoader.Completed &lt;/span&gt;&lt;span style="color: #000000;"&gt;+=&lt;/span&gt;&lt;span style="color: #000000;"&gt; (s, args) &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;24&lt;/span&gt; &lt;span style="color: #000000;"&gt;    {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;25&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (culture.Parent.IsNeutralCulture)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;26&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;27&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Search for user's region neutral resources&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;28&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;        DownloadLanguageResources(culture.Parent);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;29&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;30&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;else&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;31&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;32&lt;/span&gt; &lt;span style="color: #000000;"&gt;        RootVisual &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; Page();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;33&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;34&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Set the resource to use for all Telerik controls&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;35&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;        LocalizationManager.DefaultResourceManager &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; Strings.ResourceManager;                            
&lt;/span&gt;&lt;span style="color: #008080;"&gt;36&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;37&lt;/span&gt; &lt;span style="color: #000000;"&gt;    };
&lt;/span&gt;&lt;span style="color: #008080;"&gt;38&lt;/span&gt; &lt;span style="color: #000000;"&gt;    xapLoader.DownloadAsync();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;39&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;

&lt;p&gt;You will notice that I’m not using MEF to dynamically download the XAP files, but instead I’m using a custom &lt;strong&gt;&lt;em&gt;XapLoader&lt;/em&gt;&lt;/strong&gt; class.&amp;#160; I had two reasons for not using MEF:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;I quite new to MEF and I couldn’t figure out how to get MEF to dynamically download multiple &lt;strong&gt;&lt;em&gt;DeploymentCatalog&lt;/em&gt;&lt;/strong&gt; instances as I traverse the culture tree.&amp;#160; If a reader knows how to do this, please respond in the comments. &lt;/li&gt;

  &lt;li&gt;I wasn’t interested in the whole MEF discovery mechanism to wire up modules etc.&amp;#160; I only wanted to download the XAP file.&amp;#160; This might change at a later stage when we start refactoring On Key into a more modular approach, but for now this was unnecessary overhead that I wanted to avoid. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the source code for the &lt;strong&gt;&lt;em&gt;XapLoader&lt;/em&gt;&lt;/strong&gt; class.&amp;#160; I cannot seem to find the original link to give the original author some credit, but the code is really self explanatory so I leave it to speak for itself:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:1e9316dd-d219-40f9-9271-6b0caca23941" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 686px; height: 543px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; XAP file loader to dynamically download and load additional XAP resources at run-time
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;  [SuppressMessage(&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Microsoft.Naming&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;CA1704:IdentifiersShouldBeSpelledCorrectly&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, MessageId &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Xap&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;)]
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; XapLoader
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;readonly&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; _xapName;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt; &lt;span style="color: #000000;"&gt;    [SuppressMessage(&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Microsoft.Naming&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;CA1704:IdentifiersShouldBeSpelledCorrectly&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, MessageId &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;xap&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;)]
&lt;/span&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; XapLoader(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; xapName)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;11&lt;/span&gt; &lt;span style="color: #000000;"&gt;    {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;12&lt;/span&gt; &lt;span style="color: #000000;"&gt;        Check.ArgumentNotNullOrEmptyString(xapName, &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;xapName&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;13&lt;/span&gt; &lt;span style="color: #000000;"&gt;        _xapName &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; xapName;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;14&lt;/span&gt; &lt;span style="color: #000000;"&gt;    }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;15&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;16&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;event&lt;/span&gt;&lt;span style="color: #000000;"&gt; EventHandler&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;XapLoadedEventArgs&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; Completed;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;17&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;18&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#region&lt;/span&gt;&lt;span style="color: #000000;"&gt; Methods&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;19&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;20&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; DownloadAsync()
&lt;/span&gt;&lt;span style="color: #008080;"&gt;21&lt;/span&gt; &lt;span style="color: #000000;"&gt;    {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;22&lt;/span&gt; &lt;span style="color: #000000;"&gt;        Uri uri &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; Uri(_xapName, UriKind.Relative);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;23&lt;/span&gt; &lt;span style="color: #000000;"&gt;        WebClient wc &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; WebClient();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;24&lt;/span&gt; &lt;span style="color: #000000;"&gt;        wc.OpenReadCompleted &lt;/span&gt;&lt;span style="color: #000000;"&gt;+=&lt;/span&gt;&lt;span style="color: #000000;"&gt; OnXapLoadingResponse;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;25&lt;/span&gt; &lt;span style="color: #000000;"&gt;        wc.OpenReadAsync(uri);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;26&lt;/span&gt; &lt;span style="color: #000000;"&gt;    }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;27&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;28&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; InitXap(Stream stream)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;29&lt;/span&gt; &lt;span style="color: #000000;"&gt;    {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;30&lt;/span&gt; &lt;span style="color: #000000;"&gt;        StreamResourceInfo xapStreamInfo &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; StreamResourceInfo(stream, &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;31&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; appManifest &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; StreamReader(System.Windows.Application.GetResourceStream(
&lt;/span&gt;&lt;span style="color: #008080;"&gt;32&lt;/span&gt; &lt;span style="color: #000000;"&gt;            xapStreamInfo, 
&lt;/span&gt;&lt;span style="color: #008080;"&gt;33&lt;/span&gt; &lt;span style="color: #000000;"&gt;            &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; Uri(&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;AppManifest.xaml&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, UriKind.Relative)).Stream).ReadToEnd();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;34&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;35&lt;/span&gt; &lt;span style="color: #000000;"&gt;        XElement deploy &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; XDocument.Parse(appManifest).Root;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;36&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;37&lt;/span&gt; &lt;span style="color: #000000;"&gt;        List&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;XElement&lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; parts &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; (from assemblyParts &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;in&lt;/span&gt;&lt;span style="color: #000000;"&gt; deploy.Elements().Elements()
&lt;/span&gt;&lt;span style="color: #008080;"&gt;38&lt;/span&gt; &lt;span style="color: #000000;"&gt;                                select assemblyParts).ToList();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;39&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;40&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;foreach&lt;/span&gt;&lt;span style="color: #000000;"&gt; (XElement xe &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;in&lt;/span&gt;&lt;span style="color: #000000;"&gt; parts)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;41&lt;/span&gt; &lt;span style="color: #000000;"&gt;        {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;42&lt;/span&gt; &lt;span style="color: #000000;"&gt;            &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt; source &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; xe.Attribute(&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Source&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;).Value;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;43&lt;/span&gt; &lt;span style="color: #000000;"&gt;            AssemblyPart asmPart &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; AssemblyPart();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;44&lt;/span&gt; &lt;span style="color: #000000;"&gt;            StreamResourceInfo streamInfo &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; System.Windows.Application.GetResourceStream(
&lt;/span&gt;&lt;span style="color: #008080;"&gt;45&lt;/span&gt; &lt;span style="color: #000000;"&gt;                xapStreamInfo,
&lt;/span&gt;&lt;span style="color: #008080;"&gt;46&lt;/span&gt; &lt;span style="color: #000000;"&gt;                &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; Uri(source, UriKind.Relative));
&lt;/span&gt;&lt;span style="color: #008080;"&gt;47&lt;/span&gt; &lt;span style="color: #000000;"&gt;            asmPart.Load(streamInfo.Stream);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;48&lt;/span&gt; &lt;span style="color: #000000;"&gt;        }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;49&lt;/span&gt; &lt;span style="color: #000000;"&gt;    }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;50&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;51&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#endregion&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;52&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;53&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#region&lt;/span&gt;&lt;span style="color: #000000;"&gt; Event Handlers&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;54&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;55&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; OnXapLoadingResponse(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;object&lt;/span&gt;&lt;span style="color: #000000;"&gt; sender, OpenReadCompletedEventArgs e)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;56&lt;/span&gt; &lt;span style="color: #000000;"&gt;    {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;57&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; ((e.Error &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;) &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style="color: #000000;"&gt; (e.Cancelled &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;false&lt;/span&gt;&lt;span style="color: #000000;"&gt;))
&lt;/span&gt;&lt;span style="color: #008080;"&gt;58&lt;/span&gt; &lt;span style="color: #000000;"&gt;            InitXap(e.Result);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;59&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;60&lt;/span&gt; &lt;span style="color: #000000;"&gt;        &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (Completed &lt;/span&gt;&lt;span style="color: #000000;"&gt;!=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;61&lt;/span&gt; &lt;span style="color: #000000;"&gt;        {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;62&lt;/span&gt; &lt;span style="color: #000000;"&gt;            XapLoadedEventArgs args &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; XapLoadedEventArgs();
&lt;/span&gt;&lt;span style="color: #008080;"&gt;63&lt;/span&gt; &lt;span style="color: #000000;"&gt;            args.Error &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; e.Error;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;64&lt;/span&gt; &lt;span style="color: #000000;"&gt;            args.Cancelled &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; e.Cancelled;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;65&lt;/span&gt; &lt;span style="color: #000000;"&gt;            Completed(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt;, args);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;66&lt;/span&gt; &lt;span style="color: #000000;"&gt;        }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;67&lt;/span&gt; &lt;span style="color: #000000;"&gt;    }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;68&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;69&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#endregion&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;70&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;71&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;72&lt;/span&gt; &lt;span style="color: #000000;"&gt;  [SuppressMessage(&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Microsoft.Naming&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;CA1704:IdentifiersShouldBeSpelledCorrectly&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, MessageId &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Xap&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;)]
&lt;/span&gt;&lt;span style="color: #008080;"&gt;73&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; XapLoadedEventArgs : EventArgs
&lt;/span&gt;&lt;span style="color: #008080;"&gt;74&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;75&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#region&lt;/span&gt;&lt;span style="color: #000000;"&gt; Properties&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;76&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;77&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;bool&lt;/span&gt;&lt;span style="color: #000000;"&gt; Cancelled { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt;; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt;; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;78&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; Exception Error { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt;; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt;; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;79&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;80&lt;/span&gt; &lt;span style="color: #000000;"&gt;    &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#endregion&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;81&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Here is an example of the code in action when I start up my browser with Brazilian Portuguese as my preferred browser language:&lt;/p&gt;

&lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_ziqU4IJY4Uc/TaKos0TCGXI/AAAAAAAAAus/5JFLZhnri4g/image%5B4%5D.png?imgmax=800" width="672" height="459" /&gt; &lt;/p&gt;

&lt;p&gt;Notice how the original XAP file is downloaded and also the two subsequent request for the language specific and language neutral XAP files.&amp;#160; The language specific XAP file (pt-BR.xap) was not found, but the language neutral XAP file for Portuguese was found and the UI is therefore displayed in Portuguese using these neutral resources.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There are obviously a lot of other dimensions to consider when localizing your Silverlight application like right-to-left support, different time zones and much more.&amp;#160; Guy Smith-Ferrier covers a lot of this in his presentation so I highly recommend &lt;a href="http://www.guysmithferrier.com/2010/11/default.aspx" target="_blank"&gt;watching the video&lt;/a&gt; and/or &lt;a href="http://www.guysmithferrier.com/Downloads/I18NSilverlight.zip" target="_blank"&gt;downloading the slides&lt;/a&gt;.&amp;#160; I might follow up with another post on some of these topics at a later point in time, but for now this is about all I have to say.&amp;#160; Lekker lees &lt;img alt="Wink" src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/wink_smile.gif" /&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-8559195073451864154?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/4WR9H05FUbU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/8559195073451864154/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2011/04/pragma-on-key-silverlight-localization.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/8559195073451864154?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/8559195073451864154?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/4WR9H05FUbU/pragma-on-key-silverlight-localization.html" title="Pragma On Key Silverlight Localization" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/_ziqU4IJY4Uc/TaKor0Gtu8I/AAAAAAAAAuo/BQU6021TPUk/s72-c/Globe%5B5%5D.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2011/04/pragma-on-key-silverlight-localization.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUcMSHk8eip7ImA9WhZSGU0.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-7436086340262599568</id><published>2011-04-04T09:44:00.001+02:00</published><updated>2011-04-04T09:44:49.772+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-04T09:44:49.772+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SDLC" /><category scheme="http://www.blogger.com/atom/ns#" term="Pragma" /><category scheme="http://www.blogger.com/atom/ns#" term="TeamWork" /><title>Pragma Software Development: Check-in Procedure</title><content type="html">&lt;p&gt;When working together in a software development team it is important to have a common definition for when something is &lt;a href="http://jamesshore.com/Agile-Book/done_done.html" target="_blank"&gt;DONE&lt;/a&gt;.&amp;#160; An important aspect of getting things DONE is a well-defined check-in procedure that all developers follow to commit something into the source control repository.&amp;#160; Here is the procedure that we use at Pragma for committing changes into our Team Foundation Source Control repository:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Code has been integrated with a recent version of the code in the TFS repository – at least a version of the TFS repository on the same day. &lt;/li&gt;    &lt;li&gt;Code has been formatted according to our &lt;a href="http://www.jetbrains.com/resharper/features/code_formatting.html" target="_blank"&gt;ReSharper Pragma Full Cleanup&lt;/a&gt;&lt;em&gt;&lt;/em&gt; profile.&amp;#160; This automatically formats all code to follow the same formatting and layout standards. &lt;/li&gt;    &lt;li&gt;Code compiles without any compiler warnings. &lt;/li&gt;    &lt;li&gt;Code adheres to our coding standards - I’ll write more about this in a future post.&amp;#160; We try &lt;a href="http://fromthedevtrenches.blogspot.com/2010/06/c-coding-standards-using-resharper.html" target="_blank"&gt;to automate the application&lt;/a&gt; of our coding standards (where possible) using tools like ReSharper.&amp;#160; Alternatively, use a &lt;a href="http://csharpguidelines.codeplex.com/" target="_blank"&gt;code review checklist&lt;/a&gt; to quickly identify areas of concern.&amp;#160; &lt;/li&gt;    &lt;li&gt;No &lt;a href="http://www.jetbrains.com/resharper/features/code_analysis.html" target="_blank"&gt;ReSharper code analysis&lt;/a&gt; &lt;strong&gt;Error &lt;/strong&gt;or &lt;strong&gt;Warning&lt;/strong&gt; violations (i.e. green square in scrollbar). Any violation needs to be identified and agreed upon. &lt;strong&gt;Suggestions &lt;/strong&gt;and &lt;strong&gt;Hints&lt;/strong&gt; can be ignored if deemed unnecessary. &lt;/li&gt;    &lt;li&gt;No &lt;a href="http://fromthedevtrenches.blogspot.com/2009/11/fxcop.html" target="_blank"&gt;FxCop&lt;/a&gt; violations. Any violation needs to be identified, agreed upon and justified using the in-code &lt;a href="http://blogs.msdn.com/b/codeanalysis/archive/2006/03/23/559149.aspx" target="_blank"&gt;SuppressMessage attribute&lt;/a&gt;.&lt;/li&gt;    &lt;li&gt;New functionality has been covered by tests and the code coverage has been verified using &lt;a href="http://www.ncover.com/" target="_blank"&gt;NCover&lt;/a&gt;. &lt;/li&gt;    &lt;li&gt;Bugs have been covered by tests and verified using NCover. &lt;/li&gt;    &lt;li&gt;Code adherers to the Logging strategy and the developer has inspected the usefulness of the log statements using &lt;a href="http://fromthedevtrenches.blogspot.com/2010/08/log4view-getting-most-out-of-your.html" target="_blank"&gt;Log4View&lt;/a&gt;. &lt;/li&gt;    &lt;li&gt;Code adheres to the Exception handling strategy for managing exceptions. &lt;/li&gt;    &lt;li&gt;Error Messages and translations have been added to the resource files. &lt;/li&gt;    &lt;li&gt;The associated TFS work item (development ticket/task) has been updated to reflect the effort involved (actual hours, comments etc.)&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Once the code satisfies the above mentioned criteria, the developer runs a &lt;a href="http://www.jetbrains.com/teamcity/features/delayed_commit.html" target="_blank"&gt;gated check-in&lt;/a&gt; using the &lt;a href="http://www.jetbrains.com/teamcity" target="_blank"&gt;TeamCity&lt;/a&gt; Visual Studio Plug-in.&amp;#160; This ensures that all the unit and integration tests are executed by the TeamCity build server after integrating the local changes with the latest TFS repository changeset.&amp;#160; Only if all the tests pass will TeamCity commit the changes onto the &lt;a href="http://www.scmpatterns.com/book/pattern-summary.html" target="_blank"&gt;Mainline&lt;/a&gt;.&amp;#160;&amp;#160; The observant reader may have noticed that we don’t do an upfront &lt;a href="http://fromthedevtrenches.blogspot.com/2009/11/code-reviews.html" target="_blank"&gt;code review&lt;/a&gt;.&amp;#160; As we work &lt;a href="http://fromthedevtrenches.blogspot.com/2011/01/pragma-software-development-team.html" target="_blank"&gt;from home for 2-3 days a week&lt;/a&gt;, we conduct our code reviews on the checked-in artefacts.&amp;#160; I’ll write more about the code review procedure in a future blog posting.&amp;#160; &lt;/p&gt;  &lt;p&gt;Lastly, for service pack development, the developer needs to consider whether the change needs to be merged across to the Mainline for the next major version and merge the changes across if required.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-7436086340262599568?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/yM-_qFfr_xE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/7436086340262599568/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2011/04/pragma-software-development-check-in.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/7436086340262599568?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/7436086340262599568?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/yM-_qFfr_xE/pragma-software-development-check-in.html" title="Pragma Software Development: Check-in Procedure" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><thr:total>3</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2011/04/pragma-software-development-check-in.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUAFRXg6fSp7ImA9Wx9VGEU.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-4071653917446891842</id><published>2011-02-05T08:24:00.001+02:00</published><updated>2011-02-05T08:35:14.615+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-05T08:35:14.615+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><category scheme="http://www.blogger.com/atom/ns#" term="Pragma" /><title>Pragma Software Development Tools</title><content type="html">&lt;p&gt;&lt;a href="http://fromthedevtrenches.blogspot.com/2011/01/pragma-software-development-team.html" target="_blank"&gt;Last time around&lt;/a&gt; I mentioned I would blog about the software development tools we are using.&amp;#160; They say a picture is worth a thousand words, so with time to blog being a bit short in the week running up to the final release of On Key, here’s&amp;#160; a mind map showing the different software development tools we are using in the different software development disciplines!&amp;#160; Btw, if anybody knows about a decent Live Writer plug-in to insert a thumbnail, be sure to leave me a comment.&lt;/p&gt;  &lt;p&gt;&lt;a href="https://sites.google.com/site/fromthedevtrenches/downloads/PragmaProductsSDLCTools.png?attredirects=0" target="_blank"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Pragma Products SDLC Tools" border="0" alt="Pragma Products SDLC Tools" src="http://lh3.ggpht.com/_ziqU4IJY4Uc/TUzvnVPJs7I/AAAAAAAAAuc/3minwLHk0eE/Pragma%20Products%20SDLC%20Tools.png?imgmax=800" width="640" height="480" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-4071653917446891842?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/6Xx--zwhPtc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/4071653917446891842/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2011/02/pragma-software-development-tools.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/4071653917446891842?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/4071653917446891842?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/6Xx--zwhPtc/pragma-software-development-tools.html" title="Pragma Software Development Tools" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/_ziqU4IJY4Uc/TUzvnVPJs7I/AAAAAAAAAuc/3minwLHk0eE/s72-c/Pragma%20Products%20SDLC%20Tools.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2011/02/pragma-software-development-tools.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0QMQno6fyp7ImA9Wx9WFU0.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-6810035725752602031</id><published>2011-01-20T09:43:00.001+02:00</published><updated>2011-01-20T09:43:03.417+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-20T09:43:03.417+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SDLC" /><category scheme="http://www.blogger.com/atom/ns#" term="Pragma" /><category scheme="http://www.blogger.com/atom/ns#" term="OnKey" /><category scheme="http://www.blogger.com/atom/ns#" term="TeamWork" /><title>Pragma Software Development Team</title><content type="html">&lt;p&gt;&lt;img style="border-right-width: 0px; margin: 0px 20px 15px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="20012011" border="0" alt="20012011" align="left" src="http://lh4.ggpht.com/_ziqU4IJY4Uc/TTfnfzwBSII/AAAAAAAAAuE/nOnZVQbLX6Y/20012011%5B11%5D.jpg?imgmax=800" width="285" height="218" /&gt;Following &lt;a href="http://fromthedevtrenches.blogspot.com/2011/01/pragma-on-key-software-development.html" target="_blank"&gt;on my intention to blog&lt;/a&gt; a bit about our internal development environment here at &lt;a href="http://www.pragmaworld.net" target="_blank"&gt;PRAGMA&lt;/a&gt;, let’s start with a look at the software development team, how we communicate, where we work and what Software Development Lifecycle we follow.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h2&gt;Team&lt;/h2&gt;  &lt;p&gt;The software development team has grown quite a bit during the past 2 years.&amp;#160; Currently we have a Software Development Manager who takes the responsibility of managing the project, prioritizing the feature set, interacting with clients, ensuring the product vision etc.&amp;#160; Reporting directly to the Software Development Manager is a Development, Test and Analyst lead. They are responsible for managing the 13 developers, 3 testers and 1 analyst that compromise the rest of the team.&amp;#160;&amp;#160; The management function forms only a small part of their responsibility as they are all hands-on, doing full-time development, testing and analysis together with the rest of the team.&amp;#160; We believe in a flat structure and in the team taking collective ownership for the solution.&amp;#160; As Development Lead, I share the overall responsibility for the architecture with another senior developer in the team.&amp;#160; We also have a Project Manager/Assistant who helps with administrating the project plan and also currently plays the role of SCRUM Master.&lt;/p&gt;  &lt;h2&gt;Communication&lt;/h2&gt;  &lt;p&gt;One of the benefits of working at PRAGMA is that we get to work from home for 2 days a week.&amp;#160; Initially I found it very hard to adapt to not having the whole team co-located.&amp;#160; Especially in the early stages of the project, where I had to do a lot of mentoring, I missed the simple “luxury” of pairing with a developer to illustrate some concepts or to fledge out a design on a whiteboard or through some code.&amp;#160; As the project progressed and things settled in terms of architecture and skills the issue became less of a problem.&amp;#160; I still feel a co-located team is the most productive setup, but there is also a lot of merit in allowing people to work remotely for a day or two in the week by giving them the flexibility of not having to commute into office every day.&lt;/p&gt;  &lt;p&gt;When working remotely keeping in touch is obviously very important.&amp;#160; We use &lt;a href="http://www.skype.com/intl/en/home" target="_blank"&gt;Skype&lt;/a&gt; for IM and VOIP calls to interact between individuals and small groups of people.&amp;#160; I specifically mention small groups as we struggled to use Skype for calls that involved the whole team.&amp;#160; The call quality was not good and people would frequently drop and had to reconnect to the conference call. This might be due to bad connections from the different ISP’s that the remote workers are using so your own mileage might differ.&amp;#160; Fortunately for us PRAGMA makes use of &lt;a href="http://www.business.att.com/enterprise/Service/unified-communications-enterprise/conferencing-services-enterprise/web-conferencing-enterprise/" target="_blank"&gt;Interwise Participant&lt;/a&gt; for web conferencing so our daily feedback session currently involves a combination of using Interwise for visuals and PRAGMA’s normal teleconference facilities for audio.&amp;#160; This obviously incurs a bit of cost for the remote workers but it doesn’t nearly weigh up against the other benefits like not having to commute.&amp;#160; As the broadband scenario in South Africa is getting better and better we re-evaluate this setup every now and then to see whether we can’t get away with only using Skype.&amp;#160; For simple remote pairing/debugging sessions we find &lt;a href="http://www.hanselman.com/blog/KnowingWhenToAskForHelpMicrosoftSharedView.aspx" target="_blank"&gt;Microsoft SharedView&lt;/a&gt; to be an excellent solution. &lt;/p&gt;  &lt;h2&gt;Office Space&lt;/h2&gt;  &lt;p&gt;Our offices are located in the Bellville Business Park in the Northern Suburbs of Cape Town so fortunately we miss out on all city traffic.&amp;#160; We moved into our current premises end of November 2009 and the new, modern offices are equipped with a very nice canteen and other facilities that make working at the office a pleasure.&amp;#160; Of course there is some good, free coffee as well &lt;img alt="Smile" src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/regular_smile.gif" /&gt;&amp;#160; The seating inside the building is based on an open plan setup.&amp;#160; The software development team sit together in what is refer to as the Lab with each person having his/her own small cubicle.&amp;#160; This is a picture of my cubicle in the Lab.&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="18012011" border="0" alt="18012011" src="http://lh4.ggpht.com/_ziqU4IJY4Uc/TTfngkTa0iI/AAAAAAAAAuI/-t7txPGHydE/18012011%5B3%5D.jpg?imgmax=800" width="584" height="443" /&gt; &lt;/p&gt;  &lt;p&gt;The cubicle barriers are about 1.6 m high and allow you to work without being distracted when somebody walks by your desk.&amp;#160; This setup works quite nicely although there are some days that I feel the cubicle barriers should rather be taken down to create a feeling of more openness and to “increase communication” in the team.&amp;#160; &lt;/p&gt;  &lt;p&gt;We have whiteboards against all the walls for design discussions and two small adjacent meeting rooms to the Lab for ad-hoc design discussions and meetings.&amp;#160; We also have our build monitors setup against a wall in the Lab that shows our TeamCity builds and other dashboard related statistics relevant to our ongoing development efforts.&amp;#160; &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="18012011(001)" border="0" alt="18012011(001)" src="http://lh5.ggpht.com/_ziqU4IJY4Uc/TTfnhIdBB0I/AAAAAAAAAuM/lvPO0qLBmV0/18012011%28001%29%5B2%5D.jpg?imgmax=800" width="580" height="431" /&gt; &lt;/p&gt;  &lt;p&gt;We will hopefully be replacing the two smallish monitors with one big monitor during this year to make it easier to read as we also use these monitors as an electronic SCRUM task board during our daily at-the-office SCRUM stand-up sessions.&lt;/p&gt;  &lt;h2&gt;SDLC&lt;/h2&gt;  &lt;p&gt;Talking about &lt;a href="http://www.scrumalliance.org/" target="_blank"&gt;SCRUM&lt;/a&gt;, one of my first responsibilities when I joined the team way back in July 2008 was to look at adopting a more formal software development lifecycle.&amp;#160; I’m a firm believer in an agile development methodology and all the disciplines involved with doing agile development so we adopted &lt;a href="http://www.scrumalliance.org/" target="_blank"&gt;SCRUM&lt;/a&gt;.&amp;#160; We went through quite a few &lt;a href="http://en.wikipedia.org/wiki/Scrum_(development)#Terminology" target="_blank"&gt;Sprints&lt;/a&gt; trying out the different aspects of SCRUM to find out what works best in our environment.&amp;#160; After starting with 2 week Sprints we eventually settled on 3 weeks as our ideal Sprint length.&amp;#160; We tried &lt;a href="http://www.planningpoker.com/" target="_blank"&gt;Planning Poker&lt;/a&gt; for a few Sprints but eventually dropped this in favour of just estimating the tasks for a Sprint in Ideal hours.&amp;#160;&amp;#160; We had some big debates about using &lt;a href="http://blog.mountaingoatsoftware.com/should-companies-measure-productivity-in-story-points-ideal-days" target="_blank"&gt;Story Points versus Ideal Hours &lt;/a&gt;and how we should track our Velocity.&amp;#160; We took quite a long time to get a &lt;a href="http://en.wikipedia.org/wiki/Scrum_(development)#Product_backlog" target="_blank"&gt;Prioritized Product Backlog&lt;/a&gt; in place and also struggled to map the backlog back into a project plan that was required due to immense pressure from a big international client.&amp;#160;&amp;#160; We eventually got into some kind of SCRUM rhythm, but we still have quite a few areas where we want to improve on going forward.&amp;#160; &lt;/p&gt;  &lt;p&gt;For a start I think we need to break the team into smaller groups that focus on specific functional areas of &lt;a href="http://fromthedevtrenches.blogspot.com/2010/11/pragma-on-key-release-3-milestone.html" target="_blank"&gt;On Key&lt;/a&gt;.&amp;#160; We can then use a &lt;a href="http://www.scrumalliance.org/articles/46-advice-on-conducting-the-scrum-of-scrums-meeting" target="_blank"&gt;Scrum of Scrums&lt;/a&gt; meeting to discuss the areas of overlap and integration.&amp;#160; We also need to get better at breaking down the functionality in coarser tasks (or work items).&amp;#160; I feel we are breaking down our tasks into too fine grained work items and this causes unnecessary management overhead and also totally clutters the task board with too much detail.&amp;#160;&amp;#160; I think a lot of this is as a result of us rewriting and expanding on an existing system, i.e. we have a very good idea of what is required, but I think we must still try and manage the work at a higher level.&amp;#160;&amp;#160; This might ease the pain of integrating back into the project plan as well.&amp;#160;&amp;#160; Having said all of this, we have mastered a lot of the technical disciplines (like continuous integration, TDD, automated acceptance testing etc.) required for agile development in place and we do succeed at delivering small increments of working functionality in our 3 week Sprint cycle.&lt;/p&gt;  &lt;h2&gt;Sprint&lt;/h2&gt;  &lt;p&gt;So how does a typical 3-week Sprint look taking into account that we work remotely for about half of the time?&amp;#160; The following 3 week roster gives a quick summary of the high-level activities involved:&lt;/p&gt;  &lt;table border="1" cellspacing="0" cellpadding="2" width="693"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign="top" width="132" align="center"&gt;Mon&lt;/td&gt;        &lt;td valign="top" width="132" align="center"&gt;Tue&lt;/td&gt;        &lt;td valign="top" width="132" align="center"&gt;Wed&lt;/td&gt;        &lt;td valign="top" width="141" align="center"&gt;Thu&lt;/td&gt;        &lt;td valign="top" width="154" align="center"&gt;Fri&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="132"&gt;&lt;strong&gt;At the office&lt;/strong&gt;           &lt;br /&gt;Individual Planning and Design Discussions&lt;/td&gt;        &lt;td valign="top" width="132"&gt;&lt;strong&gt;At the office&lt;/strong&gt;           &lt;br /&gt;Daily Scrum @ 10:00           &lt;br /&gt;Daily Build @ 22:00&lt;/td&gt;        &lt;td valign="top" width="132"&gt;&lt;strong&gt;Working remotely&lt;/strong&gt;           &lt;br /&gt;Daily Scrum @ 10:00           &lt;br /&gt;Daily Build @ 22:00&lt;/td&gt;        &lt;td valign="top" width="141"&gt;&lt;strong&gt;At the office&lt;/strong&gt;           &lt;br /&gt;Daily Scrum @ 10:00           &lt;br /&gt;Daily Build @ 22:00&lt;/td&gt;        &lt;td valign="top" width="154"&gt;&lt;strong&gt;Working remotely&lt;/strong&gt;           &lt;br /&gt;Daily Scrum @ 10:00           &lt;br /&gt;Daily Build @ 22:00&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="132"&gt;&lt;strong&gt;Working Remotely&lt;/strong&gt;           &lt;br /&gt;Daily Scrum @ 10:00           &lt;br /&gt;Daily Build @ 22:00&lt;/td&gt;        &lt;td valign="top" width="132"&gt;&lt;strong&gt;At the office&lt;/strong&gt;           &lt;br /&gt;Daily Scrum @ 10:00           &lt;br /&gt;Daily Build @ 22:00&lt;/td&gt;        &lt;td valign="top" width="132"&gt;&lt;strong&gt;Working remotely&lt;/strong&gt;           &lt;br /&gt;Daily Scrum @ 10:00           &lt;br /&gt;Daily Build @ 22:00&lt;/td&gt;        &lt;td valign="top" width="141"&gt;&lt;strong&gt;At the office&lt;/strong&gt;           &lt;br /&gt;Daily Scrum @ 10:00           &lt;br /&gt;Daily Build @ 22:00&lt;/td&gt;        &lt;td valign="top" width="154"&gt;&lt;strong&gt;Working remotely&lt;/strong&gt;           &lt;br /&gt;Daily Scrum @ 10:00           &lt;br /&gt;Daily Build @ 22:00&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign="top" width="132"&gt;&lt;strong&gt;Working Remotely&lt;/strong&gt;           &lt;br /&gt;Daily Scrum @ 10:00           &lt;br /&gt;Daily Build @ 22:00&lt;/td&gt;        &lt;td valign="top" width="132"&gt;&lt;strong&gt;At the office&lt;/strong&gt;           &lt;br /&gt;Daily Scrum @ 10:00           &lt;br /&gt;Daily Build @ 22:00&lt;/td&gt;        &lt;td valign="top" width="132"&gt;&lt;strong&gt;Working remotely&lt;/strong&gt;           &lt;br /&gt;Daily Scrum @ 10:00           &lt;br /&gt;Daily Build @ 22:00&lt;/td&gt;        &lt;td valign="top" width="141"&gt;&lt;strong&gt;At the office&lt;/strong&gt;           &lt;br /&gt;Daily Scrum @ 10:00           &lt;br /&gt;Sprint Build @ 22:00&lt;/td&gt;        &lt;td valign="top" width="154"&gt;&lt;strong&gt;At the office&lt;/strong&gt;           &lt;br /&gt;Retrospective @ 09:00           &lt;br /&gt;High level Planning @ 10:00           &lt;br /&gt;Demo @ 13:00           &lt;br /&gt;Design, Training @ 14:00           &lt;br /&gt;Drinks @ 16:00&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;Well, I think that’s enough for now about the overall work environment.&amp;#160; In my next post I’ll look at the Development Tools that we are using.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-6810035725752602031?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/64DPbBAzrAs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/6810035725752602031/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2011/01/pragma-software-development-team.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6810035725752602031?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6810035725752602031?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/64DPbBAzrAs/pragma-software-development-team.html" title="Pragma Software Development Team" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_ziqU4IJY4Uc/TTfnfzwBSII/AAAAAAAAAuE/nOnZVQbLX6Y/s72-c/20012011%5B11%5D.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2011/01/pragma-software-development-team.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUGQX47cSp7ImA9Wx9WEE4.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-3395351751818079822</id><published>2011-01-14T22:33:00.001+02:00</published><updated>2011-01-14T22:33:40.009+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-14T22:33:40.009+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SDLC" /><category scheme="http://www.blogger.com/atom/ns#" term="OnKey" /><title>Pragma On Key Software Development Environment</title><content type="html">&lt;p&gt;As &lt;a href="http://fromthedevtrenches.blogspot.com/2010/11/pragma-on-key-release-3-milestone.html" target="_blank"&gt;I mentioned towards the end of last year&lt;/a&gt;, we delivered an important Release 3 milestone of Pragma On Key V5.&amp;#160; We are currently working hard to further improve the application performance and to fix the remaining bugs with the aim of going live with a big international customer 1 March 2011.&amp;#160; For those unfamiliar with PRAGMA and On Key [&lt;a href="http://www.pragmaworld.net/" target="_blank"&gt;Source&lt;/a&gt;]:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;PRAGMA is a global engineering company providing &lt;strong&gt;physical asset management improvement services and products&lt;/strong&gt; to our clients. We believe that the most important value derived from our service is &lt;strong&gt;peace of mind.&lt;/strong&gt; A client's CEO and his production or service team can focus on delivering their own client promise, whilst we, along with the in-house maintenance team, take care of optimising the performance and longevity of their assets over the life cycle of those assets.&lt;/p&gt;    &lt;p&gt;&lt;strong&gt;Pragma On Key&lt;/strong&gt; is our homegrown &lt;strong&gt;Enterprise Asset Management System (EAMS)&lt;/strong&gt;. Apart from the traditional functionalities generally expected from an EAMS, it has a variety of sophisticated modules that allow the client virtual and real-time access to asset information.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;We are based in the beautiful Cape Town, South Africa and we have customers across a wide spectrum of industries in South Africa and also overseas.&amp;#160; &lt;/p&gt;  &lt;p&gt;We currently support two major versions of On Key:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Version 4 – A Windows forms client/server application that runs on top of SQL Server as DBMS.&amp;#160; The application was developed using Delphi and has been in production for quite a few years already. &lt;/li&gt;    &lt;li&gt;Version 5 – A new web-based solution architected as a RIA application.&amp;#160; It uses Silverlight as presentation technology and a layered server architecture using .NET 4.0 on top of SQL Server as DBMS.&amp;#160;&amp;#160; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Both versions support interfacing with other ERP systems like SYSPRO and SAP via custom interfaces that we build.&amp;#160; In addition to rewriting a lot of the V4 features onto V5, we also added some really nifty new features to provide our customers with great flexibility in managing their physical assets.&amp;#160; In V5 we also started creating a SDK that allows third parties to build additional services on top of the core On Key application platform.&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;Besides these cool features in On Key itself, we have also IMO come along way in creating a solid software development environment within PRAGMA.&amp;#160; The team closed to doubled in size during the last 3 years (we are now 22 people) and we simply had to mature our SDLC practices.&amp;#160; There are of course still a lot of areas where we can and will improve on, but I think we have a good foundation to build on for the future.&lt;/p&gt;  &lt;p&gt;I want to start a series of blog posts where I write a bit about our software development environment - reflecting on the work environment, what tools and development practices we use and also areas that we want to improve on in future.&amp;#160; I also want to spend some time writing about the design of some of the core features within On Key.&amp;#160;&amp;#160; I don’t quite know how all of this is going to pan out and how many posts I am going to create, but off the cuff, here is a short list of areas that I want to cover:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Work environment – Team Composition, Office Space, SDLC (Scrum), Typical Sprint… &lt;/li&gt;    &lt;li&gt;Development Tools – Source Control, Build Server, Wiki, Work Item Management… &lt;/li&gt;    &lt;li&gt;Development Practices – Check-in procedure, Code Reviews, Coding Standards, Code Analysis (Static/Dynamic), Code Generation, TDD… &lt;/li&gt;    &lt;li&gt;Build Automation – Versioning, Continuous Integration, Continuous Performance Testing, Build Pipelines… &lt;/li&gt;    &lt;li&gt;Testing – Automated Functional Regression Testing… &lt;/li&gt;    &lt;li&gt;On Key Architecture – Client Architecture, Server Architecture, Localization, Exception Handling, Logging, Security… &lt;/li&gt;    &lt;li&gt;On Key Features – Rule Engine, Validation Framework, Background Tasks, Rollout, Synchronization… &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;This list is quite long!&amp;#160; Time permitting, I’ll try and keep posting on some topic hopefully once a week.&amp;#160; Till later…&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-3395351751818079822?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/dzLoq_H9bn0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/3395351751818079822/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2011/01/pragma-on-key-software-development.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/3395351751818079822?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/3395351751818079822?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/dzLoq_H9bn0/pragma-on-key-software-development.html" title="Pragma On Key Software Development Environment" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2011/01/pragma-on-key-software-development.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkEHQnwyfyp7ImA9Wx9XEEs.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-164089099548672852</id><published>2011-01-03T16:23:00.001+02:00</published><updated>2011-01-03T16:23:53.297+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-03T16:23:53.297+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Learning" /><title>My 2011 Software Development Reading List</title><content type="html">&lt;p&gt;A wonderful 2011 for all!&amp;#160; I’ve not made many New Year resolutions, but one resolution that I do want to try and keep is to work through my library of ever growing IT books that have been gathering some dust on my desk and hard-drive.&amp;#160; In stead of spending time reading through blogs, I want to rather concentrate on broadening/sharpening my skills through working through some of my books.&amp;#160; I’ve got quite a few good books where I’ve only read some part of the book and I also want to complete these as well.&amp;#160; So without further ado, here is my list of IT books for 2011 that I want to read:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;strong&gt;[Partially Read]&lt;/strong&gt; &lt;em&gt;Release It!: Michael T. Nygard&lt;/em&gt;&amp;#160; - Excellent advise on getting and keeping your software running in production. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;[Partially Read]&lt;/strong&gt; &lt;em&gt;Architecting Applications for the Enterprise: Dino Esposito, Andrea Saltarello&lt;/em&gt; – A great resource for all budding architects and a book that I want to re-read to evaluate our current architecture against some of the best practices mentioned in here. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;[Partially Read]&lt;/strong&gt; &lt;em&gt;Continuous Delivery: Jez Humble, David Farley&lt;/em&gt; – Excellent advise on using build, test and deployment automation to manage your software releases.&amp;#160; We’ve got quite a good deployment environment at work as &lt;a href="http://fromthedevtrenches.blogspot.com/2009/11/continuous-integration-from-theory-to.html" target="_blank"&gt;I’m a big fan of continuous integration&lt;/a&gt;, but it is always nice to read some further insights from experts to see what areas we can still improve on. &lt;/li&gt;    &lt;li&gt;&lt;em&gt;The Art of Application Performance Monitoring: Ian Molyneaux&lt;/em&gt; – Performance monitoring is high on the agenda for our &lt;a href="http://fromthedevtrenches.blogspot.com/2010/11/pragma-on-key-release-3-milestone.html" target="_blank"&gt;Enterprise Asset Management System (EAMS)&lt;/a&gt;. &lt;/li&gt;    &lt;li&gt;&lt;em&gt;Algorithms In A Nutshell: George Heineman, Gary Pollice &amp;amp; Stanley Selkow&lt;/em&gt; – Time to learn and brush up on the Graph, Search, Path finding and Network Flow algorithms.&amp;#160; I’ve got a sneaky suspicion that we are missing out on some opportunities to use better algorithms within our EAMS. &lt;/li&gt;    &lt;li&gt;&lt;em&gt;Pragmatic Thinking and Learning: Andy Hunt&lt;/em&gt; – Time to figure out the best way to think about solving problems. &lt;/li&gt;    &lt;li&gt;&lt;em&gt;Growing Software – Proven Strategies for Managing Software Engineers: Louis Testa&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;&lt;em&gt;Programming Ruby 1.9 (3rd Edition): Dave Thomas&lt;/em&gt; – Lots of people are raving about Ruby and I want to start learning why. &lt;/li&gt;    &lt;li&gt;&lt;em&gt;The Ruby Programming Language: David Flanagan &amp;amp; Yukihiro Masumoto&lt;/em&gt; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Happy reading :-)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-164089099548672852?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/kFZCRHgwa5Y" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/164089099548672852/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2011/01/my-2011-it-reading-list.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/164089099548672852?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/164089099548672852?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/kFZCRHgwa5Y/my-2011-it-reading-list.html" title="My 2011 Software Development Reading List" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2011/01/my-2011-it-reading-list.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUARH85eip7ImA9Wx9SEU8.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-2650114291318107294</id><published>2010-11-30T16:25:00.001+02:00</published><updated>2010-11-30T16:27:25.122+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-30T16:27:25.122+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="OnKey" /><title>Pragma On Key – Release 3 Milestone Reached</title><content type="html">&lt;p&gt;I’m watching the final TeamCity daily build as I type this and I’m super excited about the next major milestone that we’ve accomplished for Pragma On Key, our &lt;a href="http://www.pragmaworld.net/" target="_blank"&gt;company’s&lt;/a&gt; Enterprise Asset Management System (EAMS).&amp;#160; It’s been 30 months of hard work to re-write and extend the system using Silverlight and .NET.&amp;#160; We started off as early adopters with the Silverlight Beta’s and .NET 3.5 and with the latest build we are using Silverlight 3 and .NET 4.0 as the technology platform.&amp;#160; We evaluated Silverlight 4 but due to some unresolved memory issues in the framework we decided to stick with Silverlight 3 for now.&amp;#160; We hope to be upgrading to Silverlight 4 soon here after.&lt;/p&gt;  &lt;p&gt;I’m very proud of the way the team pulled through all the difficult times to end up with what I feel is a solid platform to build on for the future.&amp;#160; As always there is still a lot of things we can and will improve on going forward, but I think we have come along way since the start of the project.&amp;#160; From adopting a new SDLC (SCRUM) to learning a complete new technology skill set (C#; Silverlight, TDD, CI etc.) and in the process close to doubling in team size. Currently we have 2 Analysts, 5 Testers, 13 Developers (me included) and a Software Development Manager.&amp;#160;&amp;#160; I can honestly say that within the 2.5 years we only had one or two isolated incidents with the team dynamics.&amp;#160; I think this is a great testimony to the quality of the people working here at &lt;a href="http://www.pragmaworld.net/" target="_blank"&gt;Pragma&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;We are now entering the final phases of testing the new release of On Key at a big international client who is planning to go live with the system end of Feb 2011.&amp;#160; So after more than 20 000 CI builds, 230 tested builds, 26 820 commits and with just more than 9000 unit and integration tests it is great to finally see the new version of On Key coming of age!&amp;#160; We’ve got some real nifty features included in this release and I think customers will enjoy the new web based interface as well.&amp;#160; I hope to be blogging a bit more about this and our internal development environment in the future.&amp;#160; Well done to all involved!&lt;/p&gt;  &lt;p&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_ziqU4IJY4Uc/TPUJUGkW-fI/AAAAAAAAAt4/4UN7_pYQv_4/image8.png?imgmax=800" width="669" height="541" /&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-2650114291318107294?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/tlUYH4mV7Sk" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/2650114291318107294/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2010/11/pragma-on-key-release-3-milestone.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/2650114291318107294?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/2650114291318107294?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/tlUYH4mV7Sk/pragma-on-key-release-3-milestone.html" title="Pragma On Key – Release 3 Milestone Reached" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_ziqU4IJY4Uc/TPUJUGkW-fI/AAAAAAAAAt4/4UN7_pYQv_4/s72-c/image8.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2010/11/pragma-on-key-release-3-milestone.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUUMRH49eSp7ImA9Wx9TE0g.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-3412561079006504690</id><published>2010-11-21T18:29:00.001+02:00</published><updated>2010-11-21T18:34:45.061+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-21T18:34:45.061+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="DotNET" /><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>TransactionScope Fluent Interface</title><content type="html">&lt;p&gt;During the past 2 weeks I’ve been spending a lot of time investigating the performance of Pragma On Key, our &lt;a href="http://www.pragmaworld.net/" target="_blank"&gt;company’s&lt;/a&gt; Enterprise Asset Management System (EAMS).&amp;#160; Part of the investigation was to resolve some issues we were encountering with deadlocks occurring for some of the longer running transactions.&amp;#160; We are using the &lt;a href="http://msdn.microsoft.com/en-us/library/ms172152(VS.90).aspx" target="_blank"&gt;TransactionScope class&lt;/a&gt; added in .NET 2.0 to mark blocks of code in our Application Controllers as participating in a transaction.&amp;#160; Out of the box, the default &lt;a href="http://msdn.microsoft.com/en-us/library/system.transactions.isolationlevel.aspx" target="_blank"&gt;IsolationLevel&lt;/a&gt; used by new a TransactionScope instance is Serializable.&amp;#160; This ensures the best data integrity by preventing dirty reads, nonrepeatable reads and phantom rows.&amp;#160; However, all of this comes at the cost of concurrency as the range lock acquired by the DBMS prevents other transactions of updating or deleting rows in the range.&amp;#160;&amp;#160; So I set off to carefully consider the locking requirements for the different transactions to make sure we are acquiring the right level of locking for the different transactions.&lt;/p&gt;  &lt;p&gt;I’ve always found the different settings of the TransactionScope class to be rather confusing.&amp;#160; I always need to remind myself what the different items of the I&lt;a href="http://msdn.microsoft.com/en-us/library/system.transactions.isolationlevel.aspx" target="_blank"&gt;solationLevel&lt;/a&gt; and &lt;a href="http://msdn.microsoft.com/en-us/library/system.transactions.transactionscopeoption.aspx" target="_blank"&gt;TransactionScopeOption&lt;/a&gt; enumerations actually mean.&amp;#160; There is also the tricky scenario where, when passing in a new &lt;a href="http://msdn.microsoft.com/en-us/library/system.transactions.transactionoptions.aspx" target="_blank"&gt;TransactionOptions&lt;/a&gt; instance to set a different IsolationLevel, you need to remember to set the transaction Timeout value if you are using a custom Timeout setting in your web.config file.&amp;#160; So I decided to create a TransactionScopeBuilder class with a fluent interface to construct new TransactionScope instances with the idea to try and hide the complexity and also provide a more intent revealing interface of what the actual TransactionScope will do.&amp;#160; I’ll start by showing some examples usages of the builder and then conclude with the source code for the builder itself.&amp;#160; &lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt;  &lt;p&gt;The first call on the builder is a method to indicate the transactional behaviour of the scope through using the TransactionScopeOption enumeration.&amp;#160; To start a new transaction:&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:bb873bb3-85c9-4371-843f-b85d7a627d6c" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 570px; height: 125px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt;1&lt;/span&gt; &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; RequiresNew&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;2&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;TransactionScope scope &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder.StartNew();            
&lt;/span&gt;&lt;span style="color: #008080;"&gt;3&lt;/span&gt; &lt;span style="color: #000000;"&gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Required&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;4&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;TransactionScope scope &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder.StartOrJoinAmbient();  
&lt;/span&gt;&lt;span style="color: #008080;"&gt;5&lt;/span&gt; &lt;span style="color: #000000;"&gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Suppress&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;6&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;TransactionScope scope &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder.IgnoreAmbient();        &lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The next step is to then set the TransactionOptions.&amp;#160; To set the Isolation Level, call any of the following methods on the builder:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:494f1716-93cc-451c-8574-c9320813c25d" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 674px; height: 169px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt;1&lt;/span&gt; &lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; IsolationLevel.ReadUncommitted&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;2&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;TransactionScope scope &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder.StartNew().AllowDirtyReads();          
&lt;/span&gt;&lt;span style="color: #008080;"&gt;3&lt;/span&gt; &lt;span style="color: #000000;"&gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; IsolationLevel.ReadCommitted&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;4&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;TransactionScope scope &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder.StartNew().PreventDirtyReads();          
&lt;/span&gt;&lt;span style="color: #008080;"&gt;5&lt;/span&gt; &lt;span style="color: #000000;"&gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; IsolationLevel.RepeatableRead&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;6&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;TransactionScope scope &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder.StartNew().PreventNonRepeatableReads();  
&lt;/span&gt;&lt;span style="color: #008080;"&gt;7&lt;/span&gt; &lt;span style="color: #000000;"&gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; IsolationLevel.Serializable&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;8&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;TransactionScope scope &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder.StartNew().PreventPhantomReads();        &lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Having the method indicate what scenarios it will allow/prevent makes for easier reading IMO.&amp;#160; Lastly we can set the timeout associated with the transaction by calling any of the following methods on the builder:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:e47df416-8d54-4805-801d-4f4136bc1d02" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 681px; height: 80px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt;1&lt;/span&gt; &lt;span style="color: #000000;"&gt;TransactionScope scope &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder.StartNew().RunsFor(TimeSpan.FromMinutes(&lt;/span&gt;&lt;span style="color: #800080;"&gt;3&lt;/span&gt;&lt;span style="color: #000000;"&gt;));
&lt;/span&gt;&lt;span style="color: #008080;"&gt;2&lt;/span&gt; &lt;span style="color: #000000;"&gt;TransactionScope scope &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder.StartNew().RunsForMinutes(&lt;/span&gt;&lt;span style="color: #800080;"&gt;3&lt;/span&gt;&lt;span style="color: #000000;"&gt;);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;3&lt;/span&gt; &lt;span style="color: #000000;"&gt;TransactionScope scope &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder.StartNew().RunsForSeconds(&lt;/span&gt;&lt;span style="color: #800080;"&gt;180&lt;/span&gt;&lt;span style="color: #000000;"&gt;);&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;

&lt;p&gt;By defining an &lt;a href="http://msdn.microsoft.com/en-us/library/85w54y0a.aspx" target="_blank"&gt;implicit cast operator&lt;/a&gt; from my TransactionScopeBuilder to a TransactionScope, I can complete the construction process without having to do any additional method calls as illustrated above.&amp;#160; However, for scenarios where you need don’t want to assign the constructed instance to a variable (like your integration tests where you simply want to always rollback), you can complete the construction process by calling the Instance method as shown below:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:f9570b4e-d966-4e24-b104-dd364c105f19" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 575px; height: 48px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt;1&lt;/span&gt; &lt;span style="color: #0000FF;"&gt;using&lt;/span&gt;&lt;span style="color: #000000;"&gt; (TransactionScopeBuilder.StartNew().PreventPhantomReads().Instance)&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Putting all of this together, let’s look at the syntax for creating a nested TransactionScope instance:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:11112c74-523b-4c2e-acd8-65be1d718525" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 688px; height: 207px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt; 1&lt;/span&gt; &lt;span style="color: #0000FF;"&gt;using&lt;/span&gt;&lt;span style="color: #000000;"&gt; (TransactionScopeBuilder.StartNew().PreventPhantomReads().Instance)
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 2&lt;/span&gt; &lt;span style="color: #000000;"&gt;{
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 3&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;using&lt;/span&gt;&lt;span style="color: #000000;"&gt; (TransactionScope scope &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder.StartOrJoinAmbient()
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 4&lt;/span&gt; &lt;span style="color: #000000;"&gt;                                                         .PreventDirtyReads()
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 5&lt;/span&gt; &lt;span style="color: #000000;"&gt;                                                         .RunsFor(TimeSpan.FromMinutes(&lt;/span&gt;&lt;span style="color: #800080;"&gt;3&lt;/span&gt;&lt;span style="color: #000000;"&gt;)))
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 6&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 7&lt;/span&gt; &lt;span style="color: #000000;"&gt;      Assert.That(scope, Is.Not.Null);
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 8&lt;/span&gt; &lt;span style="color: #000000;"&gt;      Assert.That(Transaction.Current.IsolationLevel, Is.EqualTo(IsolationLevel.Serializable));
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 9&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;10&lt;/span&gt; &lt;span style="color: #000000;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;

&lt;p&gt;Some other benefits I get from encapsulating the construction logic in the builder are:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Ability to add logging to show when new instances are created and what the settings for the new transaction are. &lt;/li&gt;

  &lt;li&gt;Ability to enforce my own default settings for constructing new instances through reading values from configuration etc. &lt;/li&gt;

  &lt;li&gt;Ability to auto-escalate the nested transaction to the IsolationLevel of the ambient transaction.&amp;#160; As all transactions participating in the same ambient transaction needs to use the same IsolationLevel, this is especially helpful in some scenarios where the scope might differ based on the context in the which the nested transaction is being created. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The code is pretty self-explanatory, so instead of going through it line-by-line, it just include it for you to have a look at:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:9D7513F9-C04C-4721-824A-2B34F0212519:c45c3a9e-202f-49b3-9618-25e0179affdd" class="wlWriterEditableSmartContent"&gt;&lt;pre style=" width: 686px; height: 543px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"&gt;&lt;div&gt;&lt;!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/

--&gt;&lt;span style="color: #008080;"&gt;  1&lt;/span&gt; &lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;  2&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Builder Pattern to create configured &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;see cref = &amp;quot;TransactionScope&amp;quot; /&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt; instances.
&lt;/span&gt;&lt;span style="color: #008080;"&gt;  3&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;  4&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;sealed&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;class&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder
&lt;/span&gt;&lt;span style="color: #008080;"&gt;  5&lt;/span&gt; &lt;span style="color: #000000;"&gt;{
&lt;/span&gt;&lt;span style="color: #008080;"&gt;  6&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; ILogger _logger;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;  7&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; IConfigRegistry _config &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; ConfigRegistry.Instance;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;  8&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;  9&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;readonly&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;bool&lt;/span&gt;&lt;span style="color: #000000;"&gt; _autoEscalateToAmbientIsolationLevel;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 10&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; IsolationLevel _isolationLevel;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 11&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;readonly&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;bool&lt;/span&gt;&lt;span style="color: #000000;"&gt; _joinExisting;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 12&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;readonly&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeOption _scopeOptions;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 13&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; TimeSpan _timeout;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 14&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 15&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder(TransactionScopeOption scopeOptions, &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;bool&lt;/span&gt;&lt;span style="color: #000000;"&gt; autoEscalateToAmbientIsolationLevel)
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 16&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 17&lt;/span&gt; &lt;span style="color: #000000;"&gt;      Check.ArgumentNotNull(scopeOptions, &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;scopeOptions&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;);
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 18&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 19&lt;/span&gt; &lt;span style="color: #000000;"&gt;      _scopeOptions &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; scopeOptions;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 20&lt;/span&gt; &lt;span style="color: #000000;"&gt;      _joinExisting &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; scopeOptions &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeOption.Required;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 21&lt;/span&gt; &lt;span style="color: #000000;"&gt;      _autoEscalateToAmbientIsolationLevel &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; autoEscalateToAmbientIsolationLevel;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 22&lt;/span&gt; &lt;span style="color: #000000;"&gt;      _isolationLevel &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; IsolationLevel.ReadCommitted;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 23&lt;/span&gt; &lt;span style="color: #000000;"&gt;      _timeout &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; Config.DatabaseTransactionTimeout;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 24&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 25&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 26&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#region&lt;/span&gt;&lt;span style="color: #000000;"&gt; Properties&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 27&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 28&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 29&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Constructs the &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;see cref = &amp;quot;TransactionScope&amp;quot; /&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt; instance.
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 30&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 31&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 32&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScope Instance
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 33&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 34&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; Build(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt;); }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 35&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 36&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 37&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 38&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Gets or sets the logger.
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 39&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 40&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; ILogger Logger
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 41&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 42&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 43&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 44&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (_logger &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;)
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 45&lt;/span&gt; &lt;span style="color: #000000;"&gt;          {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 46&lt;/span&gt; &lt;span style="color: #000000;"&gt;              _logger &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; LoggerFactory.GetLogger(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;typeof&lt;/span&gt;&lt;span style="color: #000000;"&gt;(TransactionScopeBuilder));
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 47&lt;/span&gt; &lt;span style="color: #000000;"&gt;          }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 48&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 49&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; _logger;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 50&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 51&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt; { _logger &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; value; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 52&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 53&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 54&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 55&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Gets or sets the configuration registry.
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 56&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 57&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 58&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Gets or sets the configuration registry.
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 59&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 60&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; IConfigRegistry Config
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 61&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 62&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; _config; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 63&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;set&lt;/span&gt;&lt;span style="color: #000000;"&gt; { _config &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; value; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 64&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 65&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 66&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; IsolationLevel IsolationLevel
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 67&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 68&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; _isolationLevel; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 69&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 70&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 71&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeOption ScopeOptions
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 72&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 73&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; _scopeOptions; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 74&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 75&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 76&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; TimeSpan Timeout
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 77&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 78&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;get&lt;/span&gt;&lt;span style="color: #000000;"&gt; { &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; _timeout; }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 79&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 80&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 81&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#endregion&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 82&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 83&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#region&lt;/span&gt;&lt;span style="color: #000000;"&gt; Methods&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 84&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 85&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 86&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Creates a new &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;see cref = &amp;quot;TransactionScope&amp;quot; /&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt; that ignores the ambient
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 87&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   transaction through using &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;see cref = &amp;quot;TransactionScopeOption.Suppress&amp;quot; /&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt; option.
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 88&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 89&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder IgnoreAmbient()
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 90&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 91&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder(TransactionScopeOption.Suppress, &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;false&lt;/span&gt;&lt;span style="color: #000000;"&gt;);
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 92&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 93&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 94&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 95&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Creates a new &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;see cref = &amp;quot;TransactionScope&amp;quot; /&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt; that starts a new ambient
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 96&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   transaction through using &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;see cref = &amp;quot;TransactionScopeOption.RequiresNew&amp;quot; /&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt; option.
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 97&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 98&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder StartNew()
&lt;/span&gt;&lt;span style="color: #008080;"&gt; 99&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;100&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder(TransactionScopeOption.RequiresNew, &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;false&lt;/span&gt;&lt;span style="color: #000000;"&gt;);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;101&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;102&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;103&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;104&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Creates a new &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;see cref = &amp;quot;TransactionScope&amp;quot; /&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt; that joins the existing ambient
&lt;/span&gt;&lt;span style="color: #008080;"&gt;105&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   transaction if it exists or alternatively starts a new one through using 
&lt;/span&gt;&lt;span style="color: #008080;"&gt;106&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;see cref = &amp;quot;TransactionScopeOption.Required&amp;quot; /&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt; option.
&lt;/span&gt;&lt;span style="color: #008080;"&gt;107&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;108&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;param name = &amp;quot;autoEscalateToAmbientIsolationLevel&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;Flag to indicate whether to automatically use
&lt;/span&gt;&lt;span style="color: #008080;"&gt;109&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   the same &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;see cref = &amp;quot;IsolationLevel&amp;quot; /&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt; as the existing ambient transaction.&lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;110&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;exception cref=&amp;quot;InvalidOperationException&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;111&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; Thrown for auto escalation when the isolation level requested by nested transaction is 
&lt;/span&gt;&lt;span style="color: #008080;"&gt;112&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; finer grained than the existing ambient transaction's isolation level.
&lt;/span&gt;&lt;span style="color: #008080;"&gt;113&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/exception&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;114&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder StartOrJoinAmbient(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;bool&lt;/span&gt;&lt;span style="color: #000000;"&gt; autoEscalateToAmbientIsolationLevel &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;true&lt;/span&gt;&lt;span style="color: #000000;"&gt;)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;115&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;116&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder(TransactionScopeOption.Required, autoEscalateToAmbientIsolationLevel);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;117&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;118&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;119&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;120&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Allow dirty reads using &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;see cref = &amp;quot;System.Transactions.IsolationLevel.ReadUncommitted&amp;quot; /&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;121&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;122&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder AllowDirtyReads()
&lt;/span&gt;&lt;span style="color: #008080;"&gt;123&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;124&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; SetIsolationLevel(IsolationLevel.ReadUncommitted);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;125&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;126&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;127&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;128&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Prevent dirty reads using &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;see cref = &amp;quot;System.Transactions.IsolationLevel.ReadCommitted&amp;quot; /&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;129&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;130&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder PreventDirtyReads()
&lt;/span&gt;&lt;span style="color: #008080;"&gt;131&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;132&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; SetIsolationLevel(IsolationLevel.ReadCommitted);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;133&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;134&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;135&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;136&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Prevent non-repeatable reads using &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;see cref = &amp;quot;System.Transactions.IsolationLevel.RepeatableRead&amp;quot; /&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;137&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;138&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder PreventNonRepeatableReads()
&lt;/span&gt;&lt;span style="color: #008080;"&gt;139&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;140&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; SetIsolationLevel(IsolationLevel.RepeatableRead);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;141&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;142&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;143&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;144&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Prevent phantom reads using &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;see cref = &amp;quot;System.Transactions.IsolationLevel.Serializable&amp;quot; /&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;145&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;146&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder PreventPhantomReads()
&lt;/span&gt;&lt;span style="color: #008080;"&gt;147&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;148&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; SetIsolationLevel(IsolationLevel.Serializable);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;149&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;150&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;151&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;152&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Sets the timeout for the transaction in minutes.
&lt;/span&gt;&lt;span style="color: #008080;"&gt;153&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;154&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;param name = &amp;quot;minutes&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;The minutes to run before timeout.&lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;155&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder RunsForMinutes(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; minutes)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;156&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;157&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; RunsFor(TimeSpan.FromMinutes(minutes));
&lt;/span&gt;&lt;span style="color: #008080;"&gt;158&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;159&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;160&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;161&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Sets the timeout for the transaction in seconds.
&lt;/span&gt;&lt;span style="color: #008080;"&gt;162&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;163&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;param name = &amp;quot;seconds&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;The seconds to run before timeout.&lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;164&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder RunsForSeconds(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;int&lt;/span&gt;&lt;span style="color: #000000;"&gt; seconds)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;165&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;166&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; RunsFor(TimeSpan.FromSeconds(seconds));
&lt;/span&gt;&lt;span style="color: #008080;"&gt;167&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;168&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;169&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;170&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Sets the timeout for the transaction.
&lt;/span&gt;&lt;span style="color: #008080;"&gt;171&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;172&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;param name = &amp;quot;timeout&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;The timeout.&lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;173&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder RunsFor(TimeSpan timeout)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;174&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;175&lt;/span&gt; &lt;span style="color: #000000;"&gt;      _timeout &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; timeout;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;176&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt;;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;177&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;178&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;179&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScope Build(TransactionScopeBuilder scopeBuilder)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;180&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;181&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (Logger.IsDebugEnabled)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;182&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;183&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (scopeBuilder.ScopeOptions &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeOption.Required &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style="color: #000000;"&gt; Transaction.Current &lt;/span&gt;&lt;span style="color: #000000;"&gt;!=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;184&lt;/span&gt; &lt;span style="color: #000000;"&gt;          {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;185&lt;/span&gt; &lt;span style="color: #000000;"&gt;              Logger.Debug(&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Creating nested transaction (Scope={0};Isolation Level={1};Timeout={2}).&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, scopeBuilder.ScopeOptions, scopeBuilder.IsolationLevel, scopeBuilder.Timeout);                    
&lt;/span&gt;&lt;span style="color: #008080;"&gt;186&lt;/span&gt; &lt;span style="color: #000000;"&gt;          }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;187&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;else&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;188&lt;/span&gt; &lt;span style="color: #000000;"&gt;          {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;189&lt;/span&gt; &lt;span style="color: #000000;"&gt;              Logger.Debug(&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Creating new transaction (Scope={0};Isolation Level={1};Timeout={2}).&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, scopeBuilder.ScopeOptions, scopeBuilder.IsolationLevel, scopeBuilder.Timeout);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;190&lt;/span&gt; &lt;span style="color: #000000;"&gt;          }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;191&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }                
&lt;/span&gt;&lt;span style="color: #008080;"&gt;192&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;193&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScope(scopeBuilder.ScopeOptions, &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionOptions
&lt;/span&gt;&lt;span style="color: #008080;"&gt;194&lt;/span&gt; &lt;span style="color: #000000;"&gt;                                                              {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;195&lt;/span&gt; &lt;span style="color: #000000;"&gt;                                                                  IsolationLevel &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; scopeBuilder.IsolationLevel,
&lt;/span&gt;&lt;span style="color: #008080;"&gt;196&lt;/span&gt; &lt;span style="color: #000000;"&gt;                                                                  Timeout &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; scopeBuilder.Timeout
&lt;/span&gt;&lt;span style="color: #008080;"&gt;197&lt;/span&gt; &lt;span style="color: #000000;"&gt;                                                              });
&lt;/span&gt;&lt;span style="color: #008080;"&gt;198&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;199&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;200&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;private&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScopeBuilder SetIsolationLevel(IsolationLevel requiredLevel)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;201&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;202&lt;/span&gt; &lt;span style="color: #000000;"&gt;      IsolationLevel acceptedLevel &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; requiredLevel;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;203&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (_joinExisting &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style="color: #000000;"&gt; _autoEscalateToAmbientIsolationLevel &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style="color: #000000;"&gt; Transaction.Current &lt;/span&gt;&lt;span style="color: #000000;"&gt;!=&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;null&lt;/span&gt;&lt;span style="color: #000000;"&gt;)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;204&lt;/span&gt; &lt;span style="color: #000000;"&gt;      {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;205&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; Can only escalate to ambient level if the required level is a less-fine grained lock
&lt;/span&gt;&lt;span style="color: #008080;"&gt;206&lt;/span&gt; &lt;span style="color: #008000;"&gt;          &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; IsolationLevel Enum values: Serializable = 0; RepeatableRead = 1; ReadCommitted = 2; ReadUncommitted = 3&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;207&lt;/span&gt; &lt;span style="color: #008000;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (requiredLevel &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; Transaction.Current.IsolationLevel)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;208&lt;/span&gt; &lt;span style="color: #000000;"&gt;          {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;209&lt;/span&gt; &lt;span style="color: #000000;"&gt;              acceptedLevel &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; Transaction.Current.IsolationLevel;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;210&lt;/span&gt; &lt;span style="color: #000000;"&gt;              &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;if&lt;/span&gt;&lt;span style="color: #000000;"&gt; (Logger.IsDebugEnabled &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style="color: #000000;"&gt; requiredLevel &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt; Transaction.Current.IsolationLevel)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;211&lt;/span&gt; &lt;span style="color: #000000;"&gt;              {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;212&lt;/span&gt; &lt;span style="color: #000000;"&gt;                  Logger.Debug(&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;Building a nested transaction (Isolation Level={0}) that will auto escalate to the Ambient transaction (Isolation Level={1})&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, requiredLevel, acceptedLevel);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;213&lt;/span&gt; &lt;span style="color: #000000;"&gt;              }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;214&lt;/span&gt; &lt;span style="color: #000000;"&gt;          }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;215&lt;/span&gt; &lt;span style="color: #000000;"&gt;          &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;else&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;216&lt;/span&gt; &lt;span style="color: #000000;"&gt;          {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;217&lt;/span&gt; &lt;span style="color: #000000;"&gt;              &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;throw&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;new&lt;/span&gt;&lt;span style="color: #000000;"&gt; ArgumentException(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;string&lt;/span&gt;&lt;span style="color: #000000;"&gt;.Format(CultureInfo.InvariantCulture, &lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #800000;"&gt;TransactionScope could not be auto escalated. Requested level = {0}, Ambient Level = {1}&lt;/span&gt;&lt;span style="color: #800000;"&gt;&amp;quot;&lt;/span&gt;&lt;span style="color: #000000;"&gt;, requiredLevel, Transaction.Current.IsolationLevel));
&lt;/span&gt;&lt;span style="color: #008080;"&gt;218&lt;/span&gt; &lt;span style="color: #000000;"&gt;          }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;219&lt;/span&gt; &lt;span style="color: #000000;"&gt;      }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;220&lt;/span&gt; &lt;span style="color: #000000;"&gt;      _isolationLevel &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; acceptedLevel;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;221&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;this&lt;/span&gt;&lt;span style="color: #000000;"&gt;;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;222&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;223&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;224&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;#endregion&lt;/span&gt;&lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;225&lt;/span&gt; &lt;span style="color: #000000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;226&lt;/span&gt; &lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;227&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   Performs an implicit conversion from 
&lt;/span&gt;&lt;span style="color: #008080;"&gt;228&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;see cref = &amp;quot;Pragma.OnKey.Core.TransactionScopeBuilder&amp;quot; /&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt; to 
&lt;/span&gt;&lt;span style="color: #008080;"&gt;229&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt;   &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;see cref = &amp;quot;System.Transactions.TransactionScope&amp;quot; /&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt; by building the actual instance.
&lt;/span&gt;&lt;span style="color: #008080;"&gt;230&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;231&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;param name = &amp;quot;scopeBuilder&amp;quot;&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;The scope builder.&lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;232&lt;/span&gt; &lt;span style="color: #008000;"&gt;  &lt;/span&gt;&lt;span style="color: #808080;"&gt;///&lt;/span&gt;&lt;span style="color: #008000;"&gt; &lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;returns&amp;gt;&lt;/span&gt;&lt;span style="color: #008000;"&gt;The result of the conversion.&lt;/span&gt;&lt;span style="color: #808080;"&gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;span style="color: #808080;"&gt;
&lt;/span&gt;&lt;span style="color: #008080;"&gt;233&lt;/span&gt; &lt;span style="color: #808080;"&gt;&lt;/span&gt;&lt;span style="color: #000000;"&gt;  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;implicit&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;operator&lt;/span&gt;&lt;span style="color: #000000;"&gt; TransactionScope(TransactionScopeBuilder scopeBuilder)
&lt;/span&gt;&lt;span style="color: #008080;"&gt;234&lt;/span&gt; &lt;span style="color: #000000;"&gt;  {
&lt;/span&gt;&lt;span style="color: #008080;"&gt;235&lt;/span&gt; &lt;span style="color: #000000;"&gt;      &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; Build(scopeBuilder);
&lt;/span&gt;&lt;span style="color: #008080;"&gt;236&lt;/span&gt; &lt;span style="color: #000000;"&gt;  }
&lt;/span&gt;&lt;span style="color: #008080;"&gt;237&lt;/span&gt; &lt;span style="color: #000000;"&gt;}
&lt;/span&gt;&lt;span style="color: #008080;"&gt;238&lt;/span&gt; &lt;span style="color: #000000;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Hope you find this useful for helping you manage your own TransactionScope instances!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-3412561079006504690?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/MKAtmw_TBxc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/3412561079006504690/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2010/11/transactionscope-fluent-interface.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/3412561079006504690?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/3412561079006504690?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/MKAtmw_TBxc/transactionscope-fluent-interface.html" title="TransactionScope Fluent Interface" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2010/11/transactionscope-fluent-interface.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkEEQHo7eyp7ImA9Wx5WGEo.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-6309947477164562150</id><published>2010-09-30T21:23:00.001+02:00</published><updated>2010-09-30T21:23:21.403+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-30T21:23:21.403+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Profiling" /><category scheme="http://www.blogger.com/atom/ns#" term="DotNET" /><title>Understanding MSIL Memory Leaks</title><content type="html">&lt;p&gt;We are using a custom &lt;em&gt;RuntimeDataBuilder&lt;/em&gt; class that dynamically constructs a .NET type in-memory using Reflection.Emit to create simple property getters/setters for the information that we receive from a generic WCF Data Service. The service exposes a &amp;quot;DataSet like&amp;quot; structure consisting out of 1..m DataTableDefinition classes each containing 1..m DataTableColumnDefinition classes. When the information is received client side, we generate the dynamic type with its property setters/getters to improve the performance and facilitate binding on our Silverlight client. All of this works fine.&lt;/p&gt;  &lt;p&gt;I’m currently trying to figure out how the memory management for these custom dynamic types work.&amp;#160; I’m thinking that we might be causing a possible memory leak if we regenerate the type. Reason why I am contemplating this is that the user can change the query parameters which may then result in more/less information coming across the wire. It therefore invalidates the previous type that I created and I want to make sure that I’m are able to free up the memory used by this previous type definition as this can happen quite frequently.&amp;#160; From &lt;a href="http://msdn.microsoft.com/en-us/magazine/cc163491.aspx"&gt;this article on MSDN&lt;/a&gt; we gather that if you are using Light Weight Code Generation (LCG) the code is allocated on the managed heap which will be reclaimed by the GC when there is nothing holding a reference to it. But LCG only seems to apply to dynamic methods. My concern is for the Type with all its property getters/setters that is now not required anymore. If this is allocated on the unmanaged heap our only hope for reclaiming the memory seems to be to make sure that the type is loaded into a temporary AppDomain that we can unload when it is not required anymore.&amp;#160; This opens up a whole new can of worms for inter AppDomain communication which I would rather avoid.&lt;/p&gt;  &lt;p&gt;So my question is any of my readers can shed some more light on this topic.&amp;#160; Is my assumption correct or is there another way of reclaiming the memory?&amp;#160; I also posted &lt;a href="http://stackoverflow.com/questions/3831901/msil-memory-leaks" target="_blank"&gt;the question to StackOverflow&lt;/a&gt; if you are interested in checking out the responses over there.&amp;#160; Thx :-)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-6309947477164562150?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/EVRk9e6OmkU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/6309947477164562150/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2010/09/understanding-msil-memory-leaks.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6309947477164562150?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6309947477164562150?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/EVRk9e6OmkU/understanding-msil-memory-leaks.html" title="Understanding MSIL Memory Leaks" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><thr:total>2</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2010/09/understanding-msil-memory-leaks.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkYGQX48fSp7ImA9Wx5QE08.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-7977699413483260637</id><published>2010-09-01T07:48:00.001+02:00</published><updated>2010-09-01T07:48:40.075+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-01T07:48:40.075+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><category scheme="http://www.blogger.com/atom/ns#" term="DotNET" /><title>Ultimate .NET Development Tools 2010 Edition</title><content type="html">&lt;p&gt;Here is my updated 2010 list of development tools that I prefer to use when doing .NET development.&amp;#160; I specifically do not include any third party control/report libraries.&lt;/p&gt;  &lt;h2&gt;Categories&lt;/h2&gt;  &lt;ul&gt;   &lt;li&gt;IDE = Develop/generate/refactor code within the VS IDE or separate IDE&amp;#160; &lt;/li&gt;    &lt;li&gt;SCM = Software Configuration Management (Source Control etc.) &lt;/li&gt;    &lt;li&gt;TDD = Test Driven Development &lt;img style="border-right-width: 0px; margin: 0px 0px 0px 10px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Tools" border="0" alt="Tools" align="right" src="http://lh4.ggpht.com/_ziqU4IJY4Uc/TH3pNibwtlI/AAAAAAAAAtQ/_3eTDTS2kg0/Tools3.jpg?imgmax=800" width="240" height="180" /&gt; &lt;/li&gt;    &lt;li&gt;DBMS = Database Management Systems &lt;/li&gt;    &lt;li&gt;CI = Continuous Integration &lt;/li&gt;    &lt;li&gt;FR = Frameworks (Persistence, AOP, Inversion of Control, Logging etc.) &lt;/li&gt;    &lt;li&gt;UT = Utility Tools &lt;/li&gt;    &lt;li&gt;CA = Code Analysis (Static + Dynamic) &lt;/li&gt;    &lt;li&gt;TC = Team Collaboration (Bug tracking, Project management etc.) &lt;/li&gt;    &lt;li&gt;MD = Modelling &lt;/li&gt;    &lt;li&gt;QA = Testing Tools &lt;/li&gt;    &lt;li&gt;DP = Deployment (Installations etc.) &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;&amp;#160;&lt;/h2&gt;  &lt;h2&gt;Tools&lt;/h2&gt; * = free/open source   &lt;br /&gt;  &lt;ol&gt;   &lt;li&gt;[IDE] &lt;a href="http://msdn2.microsoft.com/en-us/vstudio/default.aspx" target="_blank"&gt;Visual Studio 2010 Premium Edition&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;[IDE] &lt;a href="http://www.jetbrains.com/resharper" target="_blank"&gt;ReSharper&lt;/a&gt; for refactoring, unit test runner and so much more &lt;/li&gt;    &lt;li&gt;[IDE] &lt;a href="http://www.codesmithtools.com/" target="_blank"&gt;CodeSmith&lt;/a&gt; for generating code.&amp;#160; Also consider T4 with &lt;a href="http://www.visualt4.com/" target="_blank"&gt;Clarius’s Visual T4&lt;/a&gt; Editor.&amp;#160;&amp;#160; &lt;/li&gt;    &lt;li&gt;[IDE]* &lt;a href="http://submain.com/products/ghostdoc.aspx" target="_blank"&gt;GhostDoc&lt;/a&gt; for inserting xml code comments &lt;/li&gt;    &lt;li&gt;[IDE] &lt;a href="http://www.altova.com/" target="_blank"&gt;Altova Xml Suite&lt;/a&gt; for any xml related work.&amp;#160; &lt;a href="http://www.wmhelp.com/" target="_blank"&gt;XmlPad&lt;/a&gt; is the best, free alternative I know of. &lt;/li&gt;    &lt;li&gt;[DBMS] &lt;a href="http://www.microsoft.com/sql/" target="_blank"&gt;SqlServer 2008&lt;/a&gt; for DBMS &lt;/li&gt;    &lt;li&gt;[SCM]* &lt;a href="http://subversion.tigris.org/" target="_blank"&gt;Subversion&lt;/a&gt; for source control &lt;/li&gt;    &lt;li&gt;[SCM]* &lt;a href="http://tortoisesvn.tigris.org/" target="_blank"&gt;TortoiseSVN&lt;/a&gt; as windows shell extension for Subversion &lt;/li&gt;    &lt;li&gt;[SCM] &lt;a href="http://tortoisesvn.tigris.org/" target="_blank"&gt;VisualSVN&lt;/a&gt; for integration of TortoiseSVN into VS.&amp;#160; &lt;a href="http://ankhsvn.open.collab.net/" target="_blank"&gt;AnkhSVN&lt;/a&gt; is the best, free alternative I know of. &lt;/li&gt;    &lt;li&gt;[SCM]* &lt;a href="http://kdiff3.sourceforge.net/" target="_blank"&gt;KDiff3&lt;/a&gt; for merging &lt;/li&gt;    &lt;li&gt;[TDD]* &lt;a href="http://www.nunit.com/" target="_blank"&gt;NUnit&lt;/a&gt; as preferred xUnit testing framework &lt;/li&gt;    &lt;li&gt;[TDD]* &lt;a href="http://code.google.com/p/moq/" target="_blank"&gt;moq&lt;/a&gt; as mock framework. &lt;/li&gt;    &lt;li&gt;[TDD] &lt;a href="http://www.ncover.com/" target="_blank"&gt;NCover&lt;/a&gt; for code coverage stats &lt;/li&gt;    &lt;li&gt;[CI]* &lt;a href="http://www.jetbrains.com/teamcity" target="_blank"&gt;TeamCity&lt;/a&gt; as build server &lt;/li&gt;    &lt;li&gt;[CI]* &lt;a href="http://msbuildextensionpack.codeplex.com/" target="_blank"&gt;MSBuild Extension Pack&lt;/a&gt; for additional MSBuild tasks. &lt;/li&gt;    &lt;li&gt;[FR]* &lt;a href="http://logging.apache.org/log4net/"&gt;log4net&lt;/a&gt; as logging framework.&amp;#160; Also see &lt;a href="http://www.log4view.com/" target="_blank"&gt;Log4View&lt;/a&gt; for an &lt;a href="http://fromthedevtrenches.blogspot.com/2010/08/log4view-getting-most-out-of-your.html" target="_blank"&gt;excellent UI&lt;/a&gt; for the log files. &lt;/li&gt;    &lt;li&gt;[FR]* &lt;a href="http://www.antlr.org/" target="_blank"&gt;ANTLR&lt;/a&gt; and &lt;a href="http://www.antlr.org/works/index.html" target="_blank"&gt;ANTLRWorks&lt;/a&gt; for creating custom DSL’s. &lt;/li&gt;    &lt;li&gt;[FR] &lt;a href="http://www.sharpcrafters.com/" target="_blank"&gt;PostSharp&lt;/a&gt; as Aspect Oriented Programming framework &lt;/li&gt;    &lt;li&gt;[FR]* &lt;a href="http://ninject.org/" target="_blank"&gt;Ninject&lt;/a&gt; as IoC container &lt;/li&gt;    &lt;li&gt;[FR] &lt;a href="http://www.mindscape.co.nz/products/LightSpeed/default.aspx" target="_blank"&gt;MindScape LightSpeed&lt;/a&gt; as my Object-Relational-Mapper.&amp;#160; &lt;a href="http://www.nhibernate.org/" target="_blank"&gt;NHibernate&lt;/a&gt; is the best free alternative I’m aware of.&amp;#160; &lt;/li&gt;    &lt;li&gt;[UT]* &lt;a href="http://www.red-gate.com/products/reflector/index.htm" target="_blank"&gt;Reflector&lt;/a&gt; to drill down to the guts of any code library (also check-out the &lt;a href="http://www.codeplex.com/reflectoraddins" target="_blank"&gt;nice plug-ins&lt;/a&gt;) &lt;/li&gt;    &lt;li&gt;[UT] &lt;a href="http://firstfloorsoftware.com/silverlightspy/" target="_blank"&gt;Silverlight Spy&lt;/a&gt; to dissect any Silverlight application. &lt;/li&gt;    &lt;li&gt;[UT] &lt;a href="http://www.regexbuddy.com/" target="_blank"&gt;RegexBuddy&lt;/a&gt; for managing those difficult regular expressions.&amp;#160; &lt;a href="http://tools.osherove.com/CoolTools/Regulator/tabid/185/Default.aspx" target="_blank"&gt;Regulator&lt;/a&gt; is the best, free alternative I know of.&amp;#160; &lt;/li&gt;    &lt;li&gt;[UT]* &lt;a href="http://www.linqpad.net/" target="_blank"&gt;LINQPad&lt;/a&gt; as a easy way to query SQL databases using LINQ and as a general scratchpad application to test C#/VB.NET code snippets. &lt;/li&gt;    &lt;li&gt;[UT]* &lt;a href="http://www.fiddlertool.com/" target="_blank"&gt;Fiddler&lt;/a&gt; to debug all your HTTP traffic in IE.&amp;#160;&amp;#160; Also see the &lt;a href="http://blogs.msdn.com/nexpert/" target="_blank"&gt;neXpert plugin&lt;/a&gt; for monitoring performance problems. &lt;/li&gt;    &lt;li&gt;[UT]* &lt;a href="http://www.getfirebug.com/" target="_blank"&gt;Firebug&lt;/a&gt; to assist with testing web applications running in Firefox. Also see &lt;a href="http://developer.yahoo.com/yslow/" target="_blank"&gt;YSlow&lt;/a&gt; add-on for performance testing and &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/60" target="_blank"&gt;Web Developer&lt;/a&gt; add-on for additional Firefox web development tools. &lt;/li&gt;    &lt;li&gt;[CA]* &lt;a href="http://msdn.microsoft.com/en-us/library/bb429476(VS.80).aspx" target="_blank"&gt;FxCop&lt;/a&gt; to enforce .NET coding guidelines &lt;/li&gt;    &lt;li&gt;[CA] &lt;a href="http://www.ndepend.com/" target="_blank"&gt;NDepend&lt;/a&gt; to get all the static code metrics I'd ever want &lt;/li&gt;    &lt;li&gt;[CA] &lt;a href="http://www.red-gate.com/products/ants_profiler/index.htm" target="_blank"&gt;ANTS Profiler&lt;/a&gt; for performance and memory profiling &lt;/li&gt;    &lt;li&gt;[MD] &lt;a href="http://www.sparxsystems.com/" target="_blank"&gt;Enterprise Architect&lt;/a&gt; to do UML Modelling and Model Driven Design if required. Alternatively use Visio with these &lt;a href="http://www.softwarestencils.com/uml/index.html"&gt;simple templates&lt;/a&gt;.&amp;#160; &lt;/li&gt;    &lt;li&gt;[MD]* &lt;a href="http://freemind.sourceforge.net/"&gt;FreeMind&lt;/a&gt; as mind mapping tool &lt;/li&gt;    &lt;li&gt;[TC]* &lt;a href="http://www.screwturn.eu/" target="_blank"&gt;ScrewTurn Wiki&lt;/a&gt; for team collaboration &lt;/li&gt;    &lt;li&gt;[QA]* &lt;a href="http://www.soapui.org/" target="_blank"&gt;Eviware soapUI&lt;/a&gt; for functional and load testing of SOA web services &lt;/li&gt;    &lt;li&gt;[QA]* &lt;a href="http://www.telerik.com/products/web-testing-tools/webaii-framework-features.aspx" target="_blank"&gt;Telerik WebAii Testing Framework&lt;/a&gt; for automated regression testing of Web 2.0 apps &lt;/li&gt;    &lt;li&gt;[DP]* &lt;a href="http://wix.sourceforge.net/"&gt;Windows Installer XML (WiX)&lt;/a&gt; for creating Windows Installers &lt;/li&gt; &lt;/ol&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-7977699413483260637?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/yYpC-3trE2s" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/7977699413483260637/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2010/09/ultimate-net-development-tools-2010.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/7977699413483260637?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/7977699413483260637?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/yYpC-3trE2s/ultimate-net-development-tools-2010.html" title="Ultimate .NET Development Tools 2010 Edition" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_ziqU4IJY4Uc/TH3pNibwtlI/AAAAAAAAAtQ/_3eTDTS2kg0/s72-c/Tools3.jpg?imgmax=800" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2010/09/ultimate-net-development-tools-2010.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkABQno4eyp7ImA9Wx5QEks.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-5213529458723788307</id><published>2010-08-31T15:19:00.001+02:00</published><updated>2010-08-31T15:19:13.433+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-08-31T15:19:13.433+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Books" /><category scheme="http://www.blogger.com/atom/ns#" term="Learning" /><title>Threading in C# – Free E-book Updated</title><content type="html">&lt;p&gt;&lt;img style="border-right-width: 0px; margin: 0px 15px 0px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="2325664001_ef61441ab7_m" border="0" alt="2325664001_ef61441ab7_m" align="left" src="http://lh6.ggpht.com/_ziqU4IJY4Uc/TH0BUB-U_2I/AAAAAAAAAtM/psa7ZxlOa0Q/2325664001_ef61441ab7_m%5B4%5D.jpg?imgmax=800" width="240" height="180" /&gt; This is just a quick post to highlight the fact that Joseph Albahari, author of the excellent &lt;a href="http://www.linqpad.net/" target="_blank"&gt;LINQPad&lt;/a&gt; and &lt;a href="http://www.albahari.com/nutshell/" target="_blank"&gt;C# 4.0 In A Nutshell&lt;/a&gt; book, has recently updated hits free &lt;a href="http://www.albahari.com/threading/" target="_blank"&gt;Threading in C# e-book&lt;/a&gt;.&amp;#160; The e-book contains some really great, concise content on all the latest threading related topics in .NET.&amp;#160; The latest version includes coverage of new .NET 4.0 constructs like ThreadLocal&amp;lt;T&amp;gt; and Lazy&amp;lt;T&amp;gt; as well as a whole chapter dedicated to the new Parallel Programming extensions to the .NET framework.&amp;#160; Highly recommended!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-5213529458723788307?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/g3IrOozEwpg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/5213529458723788307/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2010/08/threading-in-c-free-e-book-updated.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/5213529458723788307?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/5213529458723788307?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/g3IrOozEwpg/threading-in-c-free-e-book-updated.html" title="Threading in C# – Free E-book Updated" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/_ziqU4IJY4Uc/TH0BUB-U_2I/AAAAAAAAAtM/psa7ZxlOa0Q/s72-c/2325664001_ef61441ab7_m%5B4%5D.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2010/08/threading-in-c-free-e-book-updated.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEAGSHk_eCp7ImA9Wx5QEEU.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-442757743478512384</id><published>2010-08-29T14:55:00.001+02:00</published><updated>2010-08-29T14:58:49.740+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-08-29T14:58:49.740+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><title>Log4View – Getting the most out of your log4net/log4j log files</title><content type="html">&lt;p&gt;If you are using &lt;a href="http://logging.apache.org/log4net/index.html"&gt;log4net&lt;/a&gt; or &lt;a href="http://logging.apache.org/log4j/1.2/"&gt;log4j&lt;/a&gt; for writing log files, do yourself a favour and get the whole team and production support a copy of &lt;a href="http://www.log4view.com/"&gt;Log4View&lt;/a&gt; as soon as possible.&amp;#160; It really is a wonderful tool that sits on top of your log4net or log4j files to give you a birds-eye view on what’s happening in your application.&amp;#160; Need to monitor your servers remotely as they are running?&amp;#160; No problem, just add a reference to their TCP log appender that allows you to configure log4net to log all statements to a TCP port.&amp;#160; This gives you the flexibility of remotely monitoring the server as the application is running in production (providing you open the port on the firewall of course).&amp;#160; &lt;/p&gt;  &lt;p&gt;One of the most powerful features IMO is the grouping feature in the message view.&amp;#160; Look at the following screenshot that shows how easy it is to group messages according to session id/thread id or any other custom log information added to your log files.&amp;#160; Simply drag the columns you want to group by into the Group By area above the grid:&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="log4view grouping" border="0" alt="log4view grouping" src="http://lh6.ggpht.com/_ziqU4IJY4Uc/THpY2oYdR0I/AAAAAAAAAtE/u8svZ2aeQUA/image%5B9%5D.png?imgmax=800" width="640" height="379" /&gt; &lt;/p&gt;  &lt;p&gt;This specific grouping allows us to easily inspect the separate requests associated with a certain user in the system. Highly recommended!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-442757743478512384?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/Cnz0M4iavBU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/442757743478512384/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2010/08/log4view-getting-most-out-of-your.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/442757743478512384?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/442757743478512384?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/Cnz0M4iavBU/log4view-getting-most-out-of-your.html" title="Log4View – Getting the most out of your log4net/log4j log files" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/_ziqU4IJY4Uc/THpY2oYdR0I/AAAAAAAAAtE/u8svZ2aeQUA/s72-c/image%5B9%5D.png?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2010/08/log4view-getting-most-out-of-your.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkMCQns6eCp7ImA9Wx5QEE4.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-6621691880196507518</id><published>2010-08-29T00:27:00.001+02:00</published><updated>2010-08-29T00:27:43.510+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-08-29T00:27:43.510+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><category scheme="http://www.blogger.com/atom/ns#" term="OnKey" /><category scheme="http://www.blogger.com/atom/ns#" term="DotNET" /><title>RunSharp – IL Generation for Dummies</title><content type="html">&lt;p&gt;We’ve been doing some interesting work the past 2-3 weeks on creating a Rule Engine for &lt;a href="http://www.pragmaworld.net"&gt;our company’s&lt;/a&gt; flagship product, On Key.&amp;#160; The Rule Engine needs to evaluate rules entered by the end user at run-time according to our pre-defined grammar to determine a true/false answer.&amp;#160; This allows us tremendous flexibility in that end-users are able to specify under which conditions certain actions should occur within the system.&amp;#160; The main requirements for the technical solution was that it should be as quick as possible but it also has to cater for rules being changed at run-time by the end-users.&amp;#160;&amp;#160; &lt;/p&gt;  &lt;p&gt;Before heading off to create our own custom solution, we did some research to consider possible solutions to solving the same kind of problem.&amp;#160; Some of the solutions we came across were:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;a href="http://flee.codeplex.com/"&gt;Flee&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://ncalc.codeplex.com/"&gt;NCalc&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://irony.codeplex.com/"&gt;Irony&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/b/csharpfaq/archive/2009/09/14/generating-dynamic-methods-with-expression-trees-in-visual-studio-2010.aspx"&gt;Dynamic method generation using Expression Trees&lt;/a&gt;&amp;#160;&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;After looking at all of these solutions, we decided to rather create our own to give us the ultimate control and flexibility over extending the Rule Engine going forward.&amp;#160; Setting up the grammar using the excellent &lt;a href="http://www.antlr.org/"&gt;ANTLR&lt;/a&gt; and &lt;a href="http://www.antlr.org/works/index.html"&gt;ANTLRWorks&lt;/a&gt; was quite easy to do.&amp;#160; ANTLR takes care of &lt;a href="http://www.antlr.org/wiki/display/ANTLR3/Antlr+3+CSharp+Target"&gt;generating the C# code&lt;/a&gt; that will do the lexing, parsing and type checking of the rules entered by the user.&amp;#160; Thereafter we moved onto the run-time evaluation/compilation of the rules represented in the &lt;a href="http://en.wikipedia.org/wiki/Abstract_syntax_tree"&gt;Abstract Syntax Tree&lt;/a&gt; created by ANTLR.&amp;#160; For this purpose, we created 3 tree walkers/visitors on our AST to compare against each other:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Interpreter – Evaluate the rules dynamically as we walk the AST&lt;/li&gt;    &lt;li&gt;C# Code Generator – Walk the tree and generate C# code that is compiled using the C# compiler into an assembly&lt;/li&gt;    &lt;li&gt;IL Code Generator – Walk the tree and generate dynamic IL code in memory&lt;/li&gt; &lt;/ol&gt;  &lt;a name='more'&gt;&lt;/a&gt;  &lt;h2&gt;Interpreter&lt;/h2&gt;  &lt;p&gt;The main benefit of writing an interpreter is that you get rid of the complexities associated with managing rules that change at run-time as you don’t need to compile the rules.&amp;#160; You can still use caching to store a format of the constructed AST for the parsed rules to prevent the overhead of parsing/lexing the rule every time, but you don’t need to worry about unloading/loading DLL’s of code that was previously compiled.&amp;#160; The obvious down side of this solution is the performance overhead compared to compiled C# code.&lt;/p&gt;  &lt;h2&gt;C# Code Generator&lt;/h2&gt;  &lt;p&gt;The main benefit of writing a C# code generator is that we can use the C# compiler and our existing C# skill set to create rules that perform as quickly as possible.&amp;#160; The downside however is that you cannot unload an assembly out of a .NET AppDomain.&amp;#160; To support the requirement of the rules changing at run-time, we therefore would have to create a temporary AppDomain and load the assembly in there.&amp;#160; This is a technique used by the excellent &lt;a href="http://www.csscript.net/index.html"&gt;CS-Script&lt;/a&gt; to evaluate C# scripts at run-time.&amp;#160; You also need FullTrust permissions to launch the C# compiler at run-time, which is problematic for our Silverlight IIS hosted application.&lt;/p&gt;  &lt;h2&gt;IL Code Generator&lt;/h2&gt;  &lt;p&gt;The main benefit of writing a &lt;a href="http://msdn.microsoft.com/en-us/library/system.reflection.emit.aspx"&gt;IL generator&lt;/a&gt; is that it is gives you the performance equivalent to that of the compiled C# code but also the dynamics of the interpreter in the sense that you can generate the IL in memory at run-time and basically drop the &lt;a href="http://msdn.microsoft.com/en-us/library/system.reflection.emit.dynamicmethod.aspx"&gt;DynamicMethod&lt;/a&gt; from memory when rule changes are made by the end users and the rules therefore need to be recompiled.&amp;#160; However, &lt;a href="http://ayende.com/Blog/archive/2006/08/13/ReflectionEmitVsCodeDOM.aspx"&gt;generating IL directly is notoriously difficult&lt;/a&gt; and error-prone.&amp;#160; Our immediate concerns were for the technical complexities of managing this solution going forward.&amp;#160; That was until, we discovered &lt;a href="http://code.google.com/p/runsharp/"&gt;RunSharp&lt;/a&gt;.&amp;#160; We came across RunSharp in this &lt;a href="http://www.codeproject.com/KB/dotnet/runsharp.aspx"&gt;CodeProject article&lt;/a&gt;.&amp;#160; It essentially provides a run-time wrapper on top of Reflection.Emit IL generation to allow you to easily construct dynamic code at run-time.&amp;#160; To illustrate, let me take an example of C# rule generated by the C# Code Generator we created and illustrate the equivalent RunSharp code.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;u&gt;C# Code&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;   &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:b70f5804-237b-4f16-bc10-fbe312c00421" class="wlWriterEditableSmartContent"&gt;&lt;pre style="background-color:White;overflow: auto;;font-family:Consolas;font-size:12"&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;bool&lt;/span&gt;&lt;span style="color: #000000;"&gt; Rule2(IOptionValueProvider options)
{
  &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; "CA_FIL_STE_LIFTING_UNIT = 'WITH FIL STE LIFTING UNIT'"&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #000000;"&gt;
  &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; String.Compare(options.GetOptionValueAsString(&lt;/span&gt;&lt;span style="color: #800080;"&gt;1782&lt;/span&gt;&lt;span style="color: #000000;"&gt;), &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;WITH FIL STE LIFTING UNIT&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;, StringComparison.OrdinalIgnoreCase) &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;;
}
&lt;/span&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;IL Code&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:aaaacc67-1804-4278-8353-bbb8cec33815" class="wlWriterEditableSmartContent"&gt;&lt;pre style="background-color:#FFFFFF;overflow: auto;;font-family:Consolas;font-size:12"&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; Rule2CIL(TypeGen typeGen)
{
   &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; "CA_FIL_STE_LIFTING_UNIT = 'WITH FIL STE LIFTING UNIT'"&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #000000;"&gt;
   CodeGen g &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; typeGen.Public.Static.Method(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;typeof&lt;/span&gt;&lt;span style="color: #000000;"&gt; (&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;bool&lt;/span&gt;&lt;span style="color: #000000;"&gt;), &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;Rule2&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;).Parameter(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;typeof&lt;/span&gt;&lt;span style="color: #000000;"&gt; (IOptionValueProvider), &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;options&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;);
   {
       Operand result &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; Static.Invoke(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;typeof&lt;/span&gt;&lt;span style="color: #000000;"&gt; (String), &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;Compare&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;, g.Arg(&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;options&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;).Invoke(&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;GetOptionValueAsString&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #800080;"&gt;1782&lt;/span&gt;&lt;span style="color: #000000;"&gt;), &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;WITH FIL STE LIFTING UNIT&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;, StringComparison.OrdinalIgnoreCase) &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;;
       g.Return(result);
   }
}&lt;/span&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;

&lt;p&gt;You’ll see that by using the RunSharp API we are able to construct code that looks quite similar to the C# code, except that in the background RunSharp will take care of generating the IL for us.&amp;#160; RunSharp is able to provide us with such an API through the judicious use of implicit type casting and operator overloading.&amp;#160; Let’s consider a more complex rule involving multiple operands:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;C# Code&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:c4802af7-99d0-4855-a524-94596d1b2e9b" class="wlWriterEditableSmartContent"&gt;&lt;pre style="background-color:#FFFFFF;overflow: auto;;font-family:Consolas;font-size:12"&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;bool&lt;/span&gt;&lt;span style="color: #000000;"&gt; Rule10022(IOptionValueProvider options)
{
   &lt;/span&gt;&lt;span style="color: #008000;"&gt;//&lt;/span&gt;&lt;span style="color: #008000;"&gt; "CA_PACKSHAPE eq 'B' and NOT ('2755900-0100' IN CA_REBUILDING_KIT)"&lt;/span&gt;&lt;span style="color: #008000;"&gt;
&lt;/span&gt;&lt;span style="color: #000000;"&gt;
   &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;return&lt;/span&gt;&lt;span style="color: #000000;"&gt; (String.Compare(options.GetOptionValueAsString(&lt;/span&gt;&lt;span style="color: #800080;"&gt;1009&lt;/span&gt;&lt;span style="color: #000000;"&gt;), &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;B&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;, StringComparison.OrdinalIgnoreCase) &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;) &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style="color: #000000;"&gt; (&lt;/span&gt;&lt;span style="color: #000000;"&gt;!&lt;/span&gt;&lt;span style="color: #000000;"&gt;(options.CheckValueInOption(&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;2755900-0100&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #800080;"&gt;1495&lt;/span&gt;&lt;span style="color: #000000;"&gt;, OptionDataType.String)));
}&lt;/span&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;u&gt;IL Code&lt;/u&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:9f6b268e-da01-40c4-8f85-7f01f9623068" class="wlWriterEditableSmartContent"&gt;&lt;pre style="background-color:#FFFFFF;overflow: auto;;font-family:Consolas;font-size:12"&gt;&lt;span style="color: #0000FF;"&gt;public&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;static&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #0000FF;"&gt;void&lt;/span&gt;&lt;span style="color: #000000;"&gt; Rule10022CIL(TypeGen typeGen)
{
   CodeGen g &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; typeGen.Public.Static.Method(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;typeof&lt;/span&gt;&lt;span style="color: #000000;"&gt; (&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;bool&lt;/span&gt;&lt;span style="color: #000000;"&gt;), &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;Rule10022&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;).Parameter(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;typeof&lt;/span&gt;&lt;span style="color: #000000;"&gt; (IOptionValueProvider), &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;options&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;);
   {
       Operand op1 &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; Static.Invoke(&lt;/span&gt;&lt;span style="color: #0000FF;"&gt;typeof&lt;/span&gt;&lt;span style="color: #000000;"&gt; (String), &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;Compare&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;, g.Arg(&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;options&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;).Invoke(&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;GetOptionValueAsString&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #800080;"&gt;1009&lt;/span&gt;&lt;span style="color: #000000;"&gt;), &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;B&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;, StringComparison.OrdinalIgnoreCase) &lt;/span&gt;&lt;span style="color: #000000;"&gt;==&lt;/span&gt;&lt;span style="color: #000000;"&gt; &lt;/span&gt;&lt;span style="color: #800080;"&gt;0&lt;/span&gt;&lt;span style="color: #000000;"&gt;;
       Operand op2 &lt;/span&gt;&lt;span style="color: #000000;"&gt;=&lt;/span&gt;&lt;span style="color: #000000;"&gt; g.Arg(&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;options&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;).Invoke(&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;CheckValueInOption&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #800000;"&gt;2755900-0100&lt;/span&gt;&lt;span style="color: #800000;"&gt;"&lt;/span&gt;&lt;span style="color: #000000;"&gt;, &lt;/span&gt;&lt;span style="color: #800080;"&gt;1495&lt;/span&gt;&lt;span style="color: #000000;"&gt;, OptionDataType.String);
       g.Return((op1) &lt;/span&gt;&lt;span style="color: #000000;"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span style="color: #000000;"&gt; (&lt;/span&gt;&lt;span style="color: #000000;"&gt;!&lt;/span&gt;&lt;span style="color: #000000;"&gt;op2));
   }
}&lt;/span&gt;&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;

&lt;p&gt;Creating a Tree walker/visitor to traverse the AST and emit the appropriate RunSharp API calls was a snap to do and really gives us the best of both worlds - the speed of compiled code and the flexibility of managing rules that change at run-time without having to worry about the complexities of IL generation.&amp;#160; The one or two issues that we discovered were quickly corrected by the author of the library &lt;a href="http://code.google.com/u/@VhhXR1BYDhhEVgJ%2B/"&gt;Stefan Simek&lt;/a&gt;.&amp;#160; So if you ever want to create IL code at run-time again, you should really seriously consider RunSharp.&amp;#160; As the post title says, it really is IL generation for Dummies.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-6621691880196507518?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/5fmoOmkmZnU" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/6621691880196507518/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2010/08/runsharp-il-generation-for-dummies.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6621691880196507518?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6621691880196507518?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/5fmoOmkmZnU/runsharp-il-generation-for-dummies.html" title="RunSharp – IL Generation for Dummies" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2010/08/runsharp-il-generation-for-dummies.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkIHRn48cSp7ImA9WxFWE0U.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-7401262142484101983</id><published>2010-06-01T12:35:00.001+02:00</published><updated>2010-06-01T12:35:37.079+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-06-01T12:35:37.079+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Standards" /><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><category scheme="http://www.blogger.com/atom/ns#" term="TeamWork" /><title>C# Coding Standards Using ReSharper</title><content type="html">&lt;p&gt;I found the following &lt;a href="http://gojisoft.com/blog/2010/05/10/coding-standards-using-resharper/"&gt;great blog post&lt;/a&gt; by Tim Lloyd on how to setup coding standards for your development environment using &lt;a href="http://www.jetbrains.com/resharper/"&gt;ReSharper 5.0&lt;/a&gt;.&amp;#160; We’ve done pretty much the same thing in our environment although I wasn’t aware of the &lt;a href="http://rsm.codeplex.com/"&gt;ReSharper Settings Manager&lt;/a&gt; which I will test drive soon as I have found sharing settings between team members to be a real pain.&amp;#160; Seems like JetBrains will look at this for v6 though.&amp;#160; Things we are doing in addition to the content mentioned by Tim are:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Using Agent Smith to ensure the correctness of the spelling for our resource files etc. &lt;/li&gt;    &lt;li&gt;Created a more advanced layout template to order all our code using the same structure when doing &lt;a href="http://www.jetbrains.com/resharper/features/code_formatting.html"&gt;Code Cleanup&lt;/a&gt; &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;It works great if everybody in the team follows the agreed upon procedure.&amp;#160; I find that this makes code reviews focus on the right things – the actual business logic!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-7401262142484101983?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/eUh_-hB85bc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/7401262142484101983/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2010/06/c-coding-standards-using-resharper.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/7401262142484101983?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/7401262142484101983?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/eUh_-hB85bc/c-coding-standards-using-resharper.html" title="C# Coding Standards Using ReSharper" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2010/06/c-coding-standards-using-resharper.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEIHRHg6eCp7ImA9Wx5QFkQ.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-6259777402444854548</id><published>2010-04-19T10:04:00.001+02:00</published><updated>2010-09-05T15:15:35.610+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-05T15:15:35.610+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="CodeAnalysis" /><category scheme="http://www.blogger.com/atom/ns#" term="Metrics" /><title>Code Metrics</title><content type="html">&lt;p&gt;&lt;strong&gt;NOTE: This is a repost of on old post as &lt;a href="http://fromthedevtrenches.blogspot.com/2009/10/migrating-blog-onto-blogger.html"&gt;I am moving&lt;/a&gt; onto the Blogger platform&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;I've been wanting to do a post about code metrics for quite a while now - mostly to organize my thoughts on the topic as it is something that I want to introduce at work, but also to get some feedback from other people as to if and how they are using metrics to assist them in crafting quality code.&amp;#160; After reading Jeremy Miller's &lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2006/12/29/Are-Code-Statistics-Useful_3F00_.aspx"&gt;post&lt;/a&gt; on the topic, I thought I might as well take the plunge.&amp;#160;&amp;#160; I'll start by musing over what metrics I found to be useful, then continue with looking at tool support for generating these metrics and finish off with considering when to use these metrics.&lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt;  &lt;h2&gt;Metrics&lt;/h2&gt;  &lt;p&gt;I am not going to cover all the different metrics in detail but instead highlight what seems to me to be the most useful metrics and refer to articles/links where other people who have done an excellent job on covering these metrics in detail.&amp;#160; Here are the reference articles that I used:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Robert C. Martin's article on &lt;a href="http://www.objectmentor.com/resources/articles/oodmetrc.pdf"&gt;OO design quality metrics&lt;/a&gt; [1] &lt;/li&gt;    &lt;li&gt;Wikipedia's &lt;a href="http://en.wikipedia.org/wiki/Software_package_metrics"&gt;summary&lt;/a&gt; of these package metrics [2] &lt;/li&gt;    &lt;li&gt;Kirk Knoernschild's excellent &lt;a href="http://www.agilejournal.com/component/option,com_magazine/func,show_article/id,47/"&gt;introductory article&lt;/a&gt; on metrics with sample refactorings included [3] &lt;/li&gt;    &lt;li&gt;Patrick Smacchia's (developer of &lt;a href="http://www.ndepend.com"&gt;NDepend&lt;/a&gt; software) &lt;a href="http://www.ndepend.com/Metrics.aspx"&gt;excellent coverage&lt;/a&gt; on all the types of metrics supported by &lt;a href="http://www.ndepend.com"&gt;NDepend&lt;/a&gt; [4] &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.sdmetrics.com/DProp.html"&gt;Write up&lt;/a&gt; on the software metrics supported by the &lt;a href="http://www.sdmetrics.com"&gt;Software Design Metrics&lt;/a&gt; software [5] &lt;/li&gt; &lt;/ol&gt; &lt;!-- more --&gt;  &lt;h2&gt;&lt;strong&gt;Size metrics&lt;/strong&gt;&lt;/h2&gt;  &lt;p&gt;Size metrics are consistently good indicators of fault-proneness: large methods/classes/packages contain more faults [5].&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Source Lines Of Code (SLOC) &lt;/strong&gt;measures the amount of lines of code.&amp;#160; To be really useful comment lines and lines that have been broken into multiple lines need to be factored out.&amp;#160; Some people refer to this as the logical LOC vs. the physical LOC.&amp;#160; &lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;quot;2 significant advantages of &lt;i&gt;logical&lt;/i&gt; LOC over &lt;i&gt;physical&lt;/i&gt; LOC are:&lt;/p&gt;    &lt;ul&gt;     &lt;li&gt;Coding style doesn’t interfere with &lt;i&gt;logical&lt;/i&gt; LOC. For example the LOC won’t change because a method call is spawn on several lines because of a high number of argument. &lt;/li&gt;      &lt;li&gt;&lt;i&gt;logical&lt;/i&gt; LOC is independent from the language. Values obtained from assemblies written with different languages are comparable and can be summed.&amp;quot; [4] &lt;/li&gt;   &lt;/ul&gt; &lt;/blockquote&gt;  &lt;h2&gt;&lt;strong&gt;Complexity metrics&lt;/strong&gt;&lt;/h2&gt;  &lt;p&gt;There is a direct correlation between complexity and the defect rate of software, so keeping code simple is a solid first step toward lowering the defect rate of software [3].&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Cyclomatic Complexity (CC)&lt;/strong&gt; measures code complexity by counting the number of linearly independent paths through code. Complex conditionals and boolean operators increase the number of linear paths, resulting in a higher CCN. Methods with a CCN of five or higher are good refactoring candidates to help ensure code remains easy to understand [3] &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/h2&gt;  &lt;h2&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/h2&gt;  &lt;h2&gt;&lt;strong&gt;Package metrics&lt;/strong&gt;&lt;/h2&gt;  &lt;h5&gt;Coupling/Dependency metrics&lt;/h5&gt;  &lt;p&gt;Excessive dependencies between packages compromise architecture and design. Complex dependencies inhibit the testability of your system and presents numerous other challenges as presented in [1] and [3].&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Afferent Coupling (Ca)&lt;/strong&gt; measures the number of types outside a package that depend on types within the package (incoming dependencies). High afferent coupling indicates that the concerned packages have many responsibilities. [1] &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Efferent Coupling (Ce)&lt;/strong&gt; measures the number of types inside a package that depends on types outside of the package (outgoing dependencies). High efferent coupling indicates that the concerned package is dependant. [1] &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;It goes to reason that:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;&amp;quot;...afferent and efferent coupling allows you to more effectively evaluate the cost of change and the likelihood of reuse. For instance, maintaining a module with many incoming dependencies is more costly and risky since there is greater risk of impacting other modules, requiring more thorough integration testing. Conversely, a module with many outgoing dependencies is more difficult to test and reuse since all dependent modules are required ... Concrete modules with high afferent coupling will be difficult to change because of the high number of incoming dependencies. Modules with many abstractions are typically more extensible, so long as the dependencies are on the abstract portion of a module.&amp;quot;&lt;/em&gt; [3]&lt;/p&gt; &lt;/blockquote&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Instability (I) &lt;/strong&gt;measures the ratio of efferent coupling (Ce) to total coupling. I = Ce / (Ce + Ca). This metric is an indicator of the package's resilience to change. The range for this metric is 0 to 1, with I=0 indicating a completely stable package and I=1 indicating a completely instable package. [1] &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Abstractness (A) &lt;/strong&gt;measures the ratio of the number of internal abstract types (i.e abstract classes and interfaces) to the number of internal types. The range for this metric is 0 to 1, with A=0 indicating a completely concrete package and A=1 indicating a completely abstract package. [1] &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Distance from main sequence (D) &lt;/strong&gt;measures the perpendicular normalized distance of a package from the idealized line A + I = 1 (called main sequence). This metric is an indicator of the package's balance between abstractness and stability. A package squarely on the main sequence is optimally balanced with respect to its abstractness and stability. Ideal packages are either completely abstract and stable (I=0, A=1) or completely concrete and instable (I=1, A=0). The range for this metric is 0 to 1. [1][4] &lt;/li&gt; &lt;/ul&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;&amp;quot;A value approaching zero indicates a module is abstract is relation to its incoming dependencies. As distance approaches one, a module is either concrete with many incoming dependencies or abstract with many outgoing dependencies. The first case represents a lack of design integrity, while the second is useless design.&amp;quot;&lt;/em&gt; [3]&lt;/p&gt; &lt;/blockquote&gt;  &lt;h5&gt;Cohesion metrics&lt;/h5&gt;  &lt;p&gt;&lt;em&gt;&amp;quot;A low cohesive design element has been assigned many unrelated responsibilities. Consequently, the design element is more difficult to understand and therefore also harder to maintain and reuse. Design elements with low cohesion should be considered for refactoring, for instance, by extracting parts of the functionality to separate classes with clearly defined responsibilities.&amp;quot; &lt;/em&gt;[5]&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Relational Cohesion (H)&lt;/strong&gt; measures the average number of internal relationships per type. Let R be the number of type relationships that are internal to this package (i.e that do not connect to types outside the package). Let N be the number of types within the package. H = (R + 1)/ N. The extra 1 in the formula prevents H=0 when N=1. The relational cohesion represents the relationship that this package has to all its types.&amp;#160; As classes inside an package should be strongly related, the cohesion should be high. On the other hand, too high values may indicate over-coupling. A good range for RelationalCohesion is 1.5 to 4.0. Packages where RelationalCohesion &amp;lt; 1.5 or RelationalCohesion &amp;gt; 4.0 might be problematic. [4] &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Lack of Cohesion of Methods (LCOM)&lt;/strong&gt; The single responsibility principle states that a class should not have more than one reason to change. Such a class is said to be cohesive. A high LCOM value generally pinpoints a poorly cohesive class [4] &lt;/li&gt; &lt;/ul&gt;  &lt;h5&gt;Inheritance metrics&lt;/h5&gt;  &lt;p&gt;&lt;em&gt;&amp;quot;Deep inheritance structures are hypothesized to be more fault-prone. The information needed to fully understand a class situated deep in the inheritance tree is spread over several ancestor classes, thus more difficult to overview.&amp;#160; Similar to high export coupling, a modification to a design element with a large number of descendents can have a large effect on the system.&amp;quot; [5]&lt;/em&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Depth of Inheritance Tree (DIT) &lt;/strong&gt;measures the number of base classes for a class or structure.&amp;#160; Types where DIT is higher than 6 might be hard to maintain. However it is not a rule since sometime your classes might inherit from tier classes which have a high value for depth of inheritance. [4] &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;&amp;#160;&lt;/h2&gt;  &lt;h2&gt;Tools&lt;/h2&gt;  &lt;p&gt;When it comes to tools, the Mercedes Benz of .NET code metrics tools from my point of view has to be &lt;a href="http://www.ndepend.com/Default.aspx"&gt;NDepend 2.0&lt;/a&gt;.&amp;#160; &lt;a href="http://www.ndepend.com/Default.aspx"&gt;NDepend 2&lt;/a&gt; provides more than 60 metrics (including all of the metrics listed above) and includes integration into your automated build via support for MSBuild, NAnt and CruiseControl.NET.&amp;#160; Browse to &lt;a href="http://www.ndepend.com/SampleReports/OnNUnit/NDependReport.html"&gt;here&lt;/a&gt; for a sample report and &lt;a href="http://s3.amazonaws.com/NDependOnlineDemos/NDependBuildProcessIntegration_viewlet_swf.html"&gt;here&lt;/a&gt; for a demo on how to integrate it into your build.&amp;#160; &lt;/p&gt;  &lt;p&gt;There is a visual GUI (&lt;a href="http://www.ndepend.com/VisualNDepend.aspx"&gt;VisualNDepend&lt;/a&gt;) that allows you to browse your code structure and evaluate the metrics as well as a &lt;a href="http://www.ndepend.com/NDependConsole.aspx"&gt;console application&lt;/a&gt; that you can generate the metrics with.&amp;#160; Patrick has also created a &lt;strong&gt;&lt;a href="http://www.ndepend.com/CQL.htm"&gt;CQL&lt;/a&gt; (Code Query Language)&lt;/strong&gt; which allows NDepend to consider your code as a database with CQL being the query language with which you can check some assertions on this database. As a consequence, CQL is similar to SQL and supports the typical &lt;b&gt;&lt;em&gt;SELECT TOP FROM WHERE ORDER BY&lt;/em&gt;&lt;/b&gt; patterns. Here is an example of a CQL query:&lt;/p&gt;  &lt;pre&gt;&lt;p&gt;WARN IF Count &amp;gt; 0 IN SELECT METHODS 
WHERE NbILInstructions &amp;gt; 200 ORDER BY NbILInstructions DESC
// METHODS WHERE NbILInstructions &amp;gt; 200 are extremely complex and            
// should be split in smaller methods.
&lt;/p&gt;&lt;/pre&gt;

&lt;p&gt;How cool is this! To quote: &lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;&amp;quot;CQL constraints are customisable and typically tied with a particular application. For example, they can allow the specification of customized encapsulation constraints, such as, I want to ensure that this layer will never use this other layer or I want to ensure that this class will never be instantiated outside this particular namespace&lt;/em&gt;.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;VisualNDepend also provides a &lt;a href="http://www.ndepend.com/VisualNDepend.aspx#CQLEdition"&gt;CQL editor&lt;/a&gt; which supports intellisense and verbose compile error descriptions to make writing CQL queries a lot easier.&amp;#160; Enough said!&amp;#160; Browse to &lt;a href="http://www.ndepend.com/Features.aspx"&gt;here&lt;/a&gt; for a complete overview of the NDepend 2 features. &lt;/p&gt;

&lt;p&gt;Other tools that that you can have a look at include &lt;a href="http://www.campwoodsw.com/sourcemonitor.html"&gt;SourceMonitor&lt;/a&gt;, &lt;a href="http://sourceforge.net/projects/devadvantage"&gt;DevMetrics&lt;/a&gt;, &lt;a href="http://www.sdmetrics.com/"&gt;Software Design Metrics&lt;/a&gt; and &lt;a href="http://www.1bot.com/"&gt;vil&lt;/a&gt; to name a few. vil does not support .NET 2.0 and does not seem to be under active development. DevMetrics, after being open-sourced, seemed to have stagnated with no visible activity on SourceForge. SourceMonitor is actively under development and supports a variety of programming languages. However, it supports only a small subset of the metrics mentioned which does not include support for important metrics like efferent and afferent coupling etc. Software Design Metrics takes a novel approach in that it measures the complexity based on the UML models for the software. This has the advantage of being language independent, but you obviously need to have UML models to run 

  &lt;br /&gt;the analysis. &lt;/p&gt;

&lt;h2&gt;When to use&lt;/h2&gt;

&lt;p&gt;When should one use these metrics? I agree with &lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2006/12/29/Are-Code-Statistics-Useful_3F00_.aspx"&gt;Jeremy Miller in his post&lt;/a&gt; that the metrics should not replace the visual inspection/QA process and be performed in addition to it. It would be nice to have these metrics at hand to assist in the QA process though. I also agree with &lt;a href="http://softarc.blogspot.com/2006/12/code-metrics-how-useful-are-they.html"&gt;Frank Kelly in his post&lt;/a&gt; that a working system with no severity 1/2 errors and happy end users are more important than getting the right balance of Ca/Ce or whatever metric you are interested in. &lt;/p&gt;

&lt;p&gt;I think I will stick with an approach of identifying a subset of useful metrics and using these as part of an overall process of static code analysis on a regular basis. When I say regular basis I feel it should be part of your &lt;a href="http://fromthedevtrenches.blogspot.com/2009/11/continuous-integration-from-theory-to_01.html"&gt;continuous build process&lt;/a&gt; to prevent people from committing code into your repository that does not satisfy your constraints. With a tool like NDepend you can create your own custom level of acceptance criteria by which the build will fail/succeed and exclude metrics that you feel should not apply to your code base. &lt;/p&gt;

&lt;p&gt;As mentioned, the code metrics should form part of a bigger quality process that includes: &lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Visual inspection/QA via &lt;a href="http://fromthedevtrenches.blogspot.com/2009/11/code-reviews.html"&gt;peer code reviews&lt;/a&gt; (as mentioned having the metrics via a tool like VisualNDepend can greatly assist in the QA) &lt;/li&gt;

  &lt;li&gt;Automated code standards check (I prefer &lt;a href="http://fromthedevtrenches.blogspot.com/2009/11/fxcop.html"&gt;FxCop&lt;/a&gt;) &lt;/li&gt;

  &lt;li&gt;Automated code metric check (NDepend seems like the tool to use here) &lt;/li&gt;

  &lt;li&gt;Automated code coverage statistics (I prefer NCover and NCoverExplorer) &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Well, that basically covers my thoughts on the topic for now. I'm interested to know how many people are actively using metrics and what metrics they are using. I'd also like to know what processes or tools people are using to generate these metrics on their code. Let me know what's working for you in your environment.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-6259777402444854548?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/f6KkqkD8SHE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/6259777402444854548/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2010/04/code-metrics.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6259777402444854548?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6259777402444854548?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/f6KkqkD8SHE/code-metrics.html" title="Code Metrics" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2010/04/code-metrics.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUMERXY_eSp7ImA9WxBQE0o.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-7160379199922076989</id><published>2010-01-13T11:03:00.001+02:00</published><updated>2010-01-13T11:03:24.841+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-01-13T11:03:24.841+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Jobs" /><title>Vacancy: Intermediate C# Software Engineer; Cape Town - South Africa</title><content type="html">&lt;p&gt;We’ve been struggling to get some good CV’s from recruitment agencies for an intermediate-senior level C# Software Engineer.&amp;#160; I’m hoping that I might find an interested reader that fits our requirements.&amp;#160; The position is for a year contract starting as soon as possible.&amp;#160; &lt;/p&gt;  &lt;p&gt;So if you are in the Cape Town area and looking for a great opportunity to work in an agile environment (SCRUM) using the latest technologies (Silverlight 3.0, .NET 3.5, SQL Server 2008) with a strong focus on quality (TDD) send me your CV.&amp;#160; You can find more details on the position as well as our company and contact details in the job specification &lt;a href="http://sites.google.com/site/fromthedevtrenches/downloads/SoftwareEngineerJobSpec.pdf?attredirects=0&amp;amp;d=1"&gt;here&lt;/a&gt;.&amp;#160; Please include an indication of your availability as well as your current monthly remuneration.&lt;/p&gt;  &lt;p&gt;Please note:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;If you hear nothing from me, assume that we are not interested, i.e. we’ll contact you.&lt;/li&gt;    &lt;li&gt;Please no recruitment agencies. &lt;/li&gt; &lt;/ul&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-7160379199922076989?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/bDyQUyX994M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/7160379199922076989/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2010/01/vacancy-intermediate-c-software.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/7160379199922076989?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/7160379199922076989?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/bDyQUyX994M/vacancy-intermediate-c-software.html" title="Vacancy: Intermediate C# Software Engineer; Cape Town - South Africa" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2010/01/vacancy-intermediate-c-software.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkANSHgyeSp7ImA9WxFUFks.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-6153531594031129556</id><published>2009-11-01T20:59:00.001+02:00</published><updated>2010-06-27T19:46:39.691+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-06-27T19:46:39.691+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="CodeAnalysis" /><category scheme="http://www.blogger.com/atom/ns#" term="TeamWork" /><category scheme="http://www.blogger.com/atom/ns#" term="Metrics" /><title>Code Metrics</title><content type="html">&lt;strong&gt;NOTE: This is a repost of on old post as &lt;a href="http://fromthedevtrenches.blogspot.com/2009/10/migrating-blog-onto-blogger.html"&gt;I am moving&lt;/a&gt; onto the Blogger platform&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;
 I've been wanting to do a post about code metrics for quite a while now - mostly to organize my thoughts on the topic as it is something that I want to introduce at work, but also to get some feedback from other people as to if and how they are using metrics to assist them in crafting quality code.&amp;nbsp; After reading Jeremy Miller's &lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2006/12/29/Are-Code-Statistics-Useful_3F00_.aspx"&gt;post&lt;/a&gt; on the topic, I thought I might as well take the plunge.&amp;nbsp;&amp;nbsp; I'll start by musing over what metrics I found to be useful, then continue with looking at tool support for generating these metrics and finish off with considering when to use these metrics.&lt;br /&gt;
&lt;h2&gt;
Metrics&lt;/h2&gt;
I am not going to cover all the different metrics in detail but instead highlight what seems to me to be the most useful metrics and refer to articles/links where other people who have done an excellent job on covering these metrics in detail.&amp;nbsp; Here are the reference articles that I used:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Robert C. Martin's article on &lt;a href="http://www.objectmentor.com/resources/articles/oodmetrc.pdf"&gt;OO design quality metrics&lt;/a&gt; [1] &lt;/li&gt;
&lt;li&gt;Wikipedia's &lt;a href="http://en.wikipedia.org/wiki/Software_package_metrics"&gt;summary&lt;/a&gt; of these package metrics [2] &lt;/li&gt;
&lt;li&gt;Kirk Knoernschild's excellent &lt;a href="http://www.agilejournal.com/component/option,com_magazine/func,show_article/id,47/"&gt;introductory article&lt;/a&gt; on metrics with sample refactorings included [3] &lt;/li&gt;
&lt;li&gt;Patrick Smacchia's (developer of &lt;a href="http://www.ndepend.com/"&gt;NDepend&lt;/a&gt; software) &lt;a href="http://www.ndepend.com/Metrics.aspx"&gt;excellent coverage&lt;/a&gt; on all the types of metrics supported by &lt;a href="http://www.ndepend.com/"&gt;NDepend&lt;/a&gt; [4] &lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.sdmetrics.com/DProp.html"&gt;Write up&lt;/a&gt; on the software metrics supported by the &lt;a href="http://www.sdmetrics.com/"&gt;Software Design Metrics&lt;/a&gt; software [5] &lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;
&lt;strong&gt;Size metrics&lt;/strong&gt;&lt;/h4&gt;
Size metrics are consistently good indicators of fault-proneness: large methods/classes/packages contain more faults [5].&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Source Lines Of Code (SLOC) &lt;/strong&gt;measures the amount of lines of code.&amp;nbsp; To be really useful comment lines and lines that have been broken into multiple lines need to be factored out.&amp;nbsp; Some people refer to this as the logical LOC vs. the physical LOC.&amp;nbsp; &lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
"2 significant advantages of &lt;i&gt;logical&lt;/i&gt; LOC over &lt;i&gt;physical&lt;/i&gt; LOC are:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Coding style doesn’t interfere with &lt;i&gt;logical&lt;/i&gt; LOC. For example the LOC won’t change because a method call is spawn on several lines because of a high number of argument. &lt;/li&gt;
&lt;li&gt;&lt;i&gt;logical&lt;/i&gt; LOC is independent from the language. Values obtained from assemblies written with different languages are comparable and can be summed." [4] &lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
&lt;strong&gt;Complexity metrics&lt;/strong&gt;&lt;/h4&gt;
There is a direct correlation between complexity and the defect rate of software, so keeping code simple is a solid first step toward lowering the defect rate of software [3].&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cyclomatic Complexity (CC)&lt;/strong&gt; measures code complexity by counting the number of linearly independent paths through code. Complex conditionals and boolean operators increase the number of linear paths, resulting in a higher CCN. Methods with a CCN of five or higher are good refactoring candidates to help ensure code remains easy to understand [3] &lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
&lt;strong&gt;Package metrics&lt;/strong&gt;&lt;/h4&gt;
&lt;h5&gt;
Coupling/Dependency metrics&lt;/h5&gt;
Excessive dependencies between packages compromise architecture and design. Complex dependencies inhibit the testability of your system and presents numerous other challenges as presented in [1] and [3].&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Afferent Coupling (Ca)&lt;/strong&gt; measures the number of types outside a package that depend on types within the package (incoming dependencies). High afferent coupling indicates that the concerned packages have many responsibilities. [1] &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Efferent Coupling (Ce)&lt;/strong&gt; measures the number of types inside a package that depends on types outside of the package (outgoing dependencies). High efferent coupling indicates that the concerned package is dependant. [1] &lt;/li&gt;
&lt;/ul&gt;
It goes to reason that:&lt;br /&gt;
&lt;blockquote&gt;
&lt;em&gt;"...afferent and efferent coupling allows you to more effectively evaluate the cost of change and the likelihood of reuse. For instance, maintaining a module with many incoming dependencies is more costly and risky since there is greater risk of impacting other modules, requiring more thorough integration testing. Conversely, a module with many outgoing dependencies is more difficult to test and reuse since all dependent modules are required ... Concrete modules with high afferent coupling will be difficult to change because of the high number of incoming dependencies. Modules with many abstractions are typically more extensible, so long as the dependencies are on the abstract portion of a module."&lt;/em&gt; [3]&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Instability (I) &lt;/strong&gt;measures the ratio of efferent coupling (Ce) to total coupling. I = Ce / (Ce + Ca). This metric is an indicator of the package's resilience to change. The range for this metric is 0 to 1, with I=0 indicating a completely stable package and I=1 indicating a completely instable package. [1] &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Abstractness (A) &lt;/strong&gt;measures the ratio of the number of internal abstract types (i.e abstract classes and interfaces) to the number of internal types. The range for this metric is 0 to 1, with A=0 indicating a completely concrete package and A=1 indicating a completely abstract package. [1] &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distance from main sequence (D) &lt;/strong&gt;measures the perpendicular normalized distance of a package from the idealized line A + I = 1 (called main sequence). This metric is an indicator of the package's balance between abstractness and stability. A package squarely on the main sequence is optimally balanced with respect to its abstractness and stability. Ideal packages are either completely abstract and stable (I=0, A=1) or completely concrete and instable (I=1, A=0). The range for this metric is 0 to 1. [1][4] &lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;em&gt;"A value approaching zero indicates a module is abstract is relation to its incoming dependencies. As distance approaches one, a module is either concrete with many incoming dependencies or abstract with many outgoing dependencies. The first case represents a lack of design integrity, while the second is useless design."&lt;/em&gt; [3]&lt;/blockquote&gt;
&lt;h5&gt;
Cohesion metrics&lt;/h5&gt;
&lt;em&gt;"A low cohesive design element has been assigned many unrelated responsibilities. Consequently, the design element is more difficult to understand and therefore also harder to maintain and reuse. Design elements with low cohesion should be considered for refactoring, for instance, by extracting parts of the functionality to separate classes with clearly defined responsibilities." &lt;/em&gt;[5]&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Relational Cohesion (H)&lt;/strong&gt; measures the average number of internal relationships per type. Let R be the number of type relationships that are internal to this package (i.e that do not connect to types outside the package). Let N be the number of types within the package. H = (R + 1)/ N. The extra 1 in the formula prevents H=0 when N=1. The relational cohesion represents the relationship that this package has to all its types.&amp;nbsp; As classes inside an package should be strongly related, the cohesion should be high. On the other hand, too high values may indicate over-coupling. A good range for RelationalCohesion is 1.5 to 4.0. Packages where RelationalCohesion &amp;lt; 1.5 or RelationalCohesion &amp;gt; 4.0 might be problematic. [4] &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lack of Cohesion of Methods (LCOM)&lt;/strong&gt; The single responsibility principle states that a class should not have more than one reason to change. Such a class is said to be cohesive. A high LCOM value generally pinpoints a poorly cohesive class [4] &lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;
Inheritance metrics&lt;/h5&gt;
&lt;em&gt;"Deep inheritance structures are hypothesized to be more fault-prone. The information needed to fully understand a class situated deep in the inheritance tree is spread over several ancestor classes, thus more difficult to overview.&amp;nbsp; Similar to high export coupling, a modification to a design element with a large number of descendents can have a large effect on the system." [5]&lt;/em&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Depth of Inheritance Tree (DIT) &lt;/strong&gt;measures the number of base classes for a class or structure.&amp;nbsp; Types where DIT is higher than 6 might be hard to maintain. However it is not a rule since sometime your classes might inherit from tier classes which have a high value for depth of inheritance. [4] &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
Tools&lt;/h2&gt;
When it comes to tools, the Mercedes Benz of .NET code metrics tools from my point of view has to be &lt;a href="http://www.ndepend.com/Default.aspx"&gt;NDepend 2.0&lt;/a&gt;.&amp;nbsp; &lt;a href="http://www.ndepend.com/Default.aspx"&gt;NDepend 2&lt;/a&gt; provides more than 60 metrics (including all of the metrics listed above) and includes integration into your automated build via support for MSBuild, NAnt and CruiseControl.NET.&amp;nbsp; Browse to &lt;a href="http://www.ndepend.com/SampleReports/OnNUnit/NDependReport.html"&gt;here&lt;/a&gt; for a sample report and &lt;a href="http://s3.amazonaws.com/NDependOnlineDemos/NDependBuildProcessIntegration_viewlet_swf.html"&gt;here&lt;/a&gt; for a demo on how to integrate it into your build.&amp;nbsp; &lt;br /&gt;
There is a visual GUI (&lt;a href="http://www.ndepend.com/VisualNDepend.aspx"&gt;VisualNDepend&lt;/a&gt;) that allows you to browse your code structure and evaluate the metrics as well as a &lt;a href="http://www.ndepend.com/NDependConsole.aspx"&gt;console application&lt;/a&gt; that you can generate the metrics with.&amp;nbsp; Patrick has also created a &lt;strong&gt;&lt;a href="http://www.ndepend.com/CQL.htm"&gt;CQL&lt;/a&gt; (Code Query Language)&lt;/strong&gt; which allows NDepend to consider your code as a database with CQL being the query language with which you can check some assertions on this database. As a consequence, CQL is similar to SQL and supports the typical &lt;b&gt;&lt;em&gt;SELECT TOP FROM WHERE ORDER BY&lt;/em&gt;&lt;/b&gt; patterns. Here is an example of a CQL query:&lt;br /&gt;
&lt;pre&gt;&lt;br /&gt;
WARN IF Count &amp;gt; 0 IN SELECT METHODS 
WHERE NbILInstructions &amp;gt; 200 ORDER BY NbILInstructions DESC
// METHODS WHERE NbILInstructions &amp;gt; 200 are extremely complex and            
// should be split in smaller methods.
&lt;br /&gt;
&lt;/pre&gt;
How cool is this! To quote: &lt;br /&gt;
&lt;blockquote&gt;
&lt;em&gt;"CQL constraints are customisable and typically tied with a particular application. For example, they can allow the specification of customized encapsulation constraints, such as, I want to ensure that this layer will never use this other layer or I want to ensure that this class will never be instantiated outside this particular namespace&lt;/em&gt;."&lt;/blockquote&gt;
VisualNDepend also provides a &lt;a href="http://www.ndepend.com/VisualNDepend.aspx#CQLEdition"&gt;CQL editor&lt;/a&gt; which supports intellisense and verbose compile error descriptions to make writing CQL queries a lot easier.&amp;nbsp; Enough said!&amp;nbsp; Browse to &lt;a href="http://www.ndepend.com/Features.aspx"&gt;here&lt;/a&gt; for a complete overview of the NDepend 2 features. &lt;br /&gt;
Other tools that that you can have a look at include &lt;a href="http://www.campwoodsw.com/sourcemonitor.html"&gt;SourceMonitor&lt;/a&gt;, &lt;a href="http://sourceforge.net/projects/devadvantage"&gt;DevMetrics&lt;/a&gt;, &lt;a href="http://www.sdmetrics.com/"&gt;Software Design Metrics&lt;/a&gt; and &lt;a href="http://www.1bot.com/"&gt;vil&lt;/a&gt; to name a few. vil does not support .NET 2.0 and does not seem to be under active development. DevMetrics, after being open-sourced, seemed to have stagnated with no visible activity on SourceForge. SourceMonitor is actively under development and supports a variety of programming languages. However, it supports only a small subset of the metrics mentioned which does not include support for important metrics like efferent and afferent coupling etc. Software Design Metrics takes a novel approach in that it measures the complexity based on the UML models for the software. This has the advantage of being language independent, but you obviously need to have UML models to run 

  &lt;br /&gt;the analysis. &lt;br /&gt;
&lt;h2&gt;
When to use&lt;/h2&gt;
When should one use these metrics? I agree with &lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2006/12/29/Are-Code-Statistics-Useful_3F00_.aspx"&gt;Jeremy Miller in his post&lt;/a&gt; that the metrics should not replace the visual inspection/QA process and be performed in addition to it. It would be nice to have these metrics at hand to assist in the QA process though. I also agree with &lt;a href="http://softarc.blogspot.com/2006/12/code-metrics-how-useful-are-they.html"&gt;Frank Kelly in his post&lt;/a&gt; that a working system with no severity 1/2 errors and happy end users are more important than getting the right balance of Ca/Ce or whatever metric you are interested in. &lt;br /&gt;
I think I will stick with an approach of identifying a subset of useful metrics and using these as part of an overall process of static code analysis on a regular basis. When I say regular basis I feel it should be part of your &lt;a href="http://fromthedevtrenches.blogspot.com/2009/11/continuous-integration-from-theory-to_01.html"&gt;continuous build process&lt;/a&gt; to prevent people from committing code into your repository that does not satisfy your constraints. With a tool like NDepend you can create your own custom level of acceptance criteria by which the build will fail/succeed and exclude metrics that you feel should not apply to your code base. &lt;br /&gt;
As mentioned, the code metrics should form part of a bigger quality process that includes: &lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Visual inspection/QA via &lt;a href="http://fromthedevtrenches.blogspot.com/2009/11/code-reviews.html"&gt;peer code reviews&lt;/a&gt; (as mentioned having the metrics via a tool like VisualNDepend can greatly assist in the QA) &lt;/li&gt;
&lt;li&gt;Automated code standards check (I prefer &lt;a href="http://fromthedevtrenches.blogspot.com/2009/11/fxcop.html"&gt;FxCop&lt;/a&gt;) &lt;/li&gt;
&lt;li&gt;Automated code metric check (NDepend seems like the tool to use here) &lt;/li&gt;
&lt;li&gt;Automated code coverage statistics (I prefer NCover and NCoverExplorer) &lt;/li&gt;
&lt;/ul&gt;
Well, that basically covers my thoughts on the topic for now. I'm interested to know how many people are actively using metrics and what metrics they are using. I'd also like to know what processes or tools people are using to generate these metrics on their code. Let me know what's working for you in your environment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-6153531594031129556?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/ym_YsOinL00" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/6153531594031129556/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2009/11/code-metrics.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6153531594031129556?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6153531594031129556?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/ym_YsOinL00/code-metrics.html" title="Code Metrics" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><thr:total>1</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2009/11/code-metrics.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0EGRXk6eyp7ImA9Wx5QFkQ.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-3315957687821968027</id><published>2009-11-01T20:58:00.001+02:00</published><updated>2010-09-05T15:00:24.713+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-05T15:00:24.713+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="CodeReviews" /><category scheme="http://www.blogger.com/atom/ns#" term="TeamWork" /><title>Code Reviews</title><content type="html">&lt;p&gt;&lt;strong&gt;NOTE: This is a repost of on old post as &lt;a href="http://fromthedevtrenches.blogspot.com/2009/10/migrating-blog-onto-blogger.html"&gt;I am moving&lt;/a&gt; onto the Blogger platform&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;Code reviews are a proven, effective way to minimize defects, improve code quality and keep code more maintainable.&amp;#160; It encourages team collaboration and assists with mentoring developers. Yet, not many projects employ code reviews as a regular part of their development process. Why is this?&amp;#160; Programmer egos and the hassles of packaging source code for review are often sited as some reasons for not doing code reviews. &lt;/p&gt;  &lt;p&gt;I felt that code reviews should form part of a good code quality control process that includes: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Visual inspection/QA via peer code reviews &lt;/li&gt;    &lt;li&gt;Automated code standards check (I prefer &lt;a href="http://blogs.msdn.com/fxcop/"&gt;FxCop&lt;/a&gt;) &lt;/li&gt;    &lt;li&gt;Automated code metrics check (I prefer &lt;a href="http://www.ndepend.com/"&gt;NDepend&lt;/a&gt;) &lt;/li&gt;    &lt;li&gt;Automated code coverage statistics (I prefer &lt;a href="http://ncover.org/site/"&gt;NCover&lt;/a&gt; and &lt;a href="http://www.kiwidude.com/dotnet/DownloadPage.html"&gt;NCoverExplorer&lt;/a&gt;) &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;In this post I will spend some time looking at code reviews.&amp;#160; I'll start by considering different styles of code review and some code review metrics. I'll then move on to some thoughts on review frequencies and best practices for peer code review.&amp;#160; I'll finish off by considering some tools that can assist with the code review process itself. &lt;/p&gt; &lt;a name='more'&gt;&lt;/a&gt;  &lt;h2&gt;References&lt;/h2&gt;  &lt;p&gt;I used the following books and articles to organize my thoughts on the topic: &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;a href="http://www.smartbear.com/"&gt;Smart Bear Software's&lt;/a&gt; free, excellent book &lt;em&gt;&lt;a href="http://codereviewbook.com/"&gt;Best Kept Secrets of Peer Code Review&lt;/a&gt;&lt;/em&gt;. [Cohen01] &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.smartbear.com/"&gt;Smart Bear Software's&lt;/a&gt; whitepaper on &lt;a href="http://www.smartbearsoftware.com/docs/BestPracticesForPeerCodeReview.pdf"&gt;&lt;em&gt;Best Practices for Peer Code Review&lt;/em&gt;&lt;/a&gt;. [Cohen02] &lt;/li&gt;    &lt;li&gt;Robert Bogue's article on &lt;i&gt;&lt;a href="http://www.developer.com/java/other/article.php/3579756"&gt;Effective Code Reviews Without the Pain&lt;/a&gt;&lt;/i&gt;. [Bogue] &lt;/li&gt;    &lt;li&gt;Wikipedia article on &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Code_review"&gt;Code Review&lt;/a&gt;&lt;/i&gt;. [Wikipedia01] &lt;/li&gt;    &lt;li&gt;Wikipedia article on &lt;a href="http://en.wikipedia.org/wiki/Hawthorne_effect"&gt;&lt;em&gt;Hawtorne Effect&lt;/em&gt;&lt;/a&gt;. [Wikipedia02] &lt;/li&gt; &lt;/ol&gt;  &lt;h2&gt;Review Types&lt;/h2&gt;  &lt;p&gt;Code review practices often fall into two main categories: formal code review and lightweight code review. &lt;/p&gt;  &lt;h5&gt;Formal Code Review&lt;/h5&gt;  &lt;p&gt;Formal code review, such as a &lt;a href="http://en.wikipedia.org/wiki/Fagan_inspection"&gt;Fagan inspection&lt;/a&gt;, involves a careful and detailed process with multiple participants and multiple phases. Software developers attend a series of meetings and review code line by line, usually using printed copies of the material. An &lt;b&gt;Introductory meeting&lt;/b&gt; is held where the goals and rules for the review are explained and the review material is handed out. Reviewers inspect the code privately and feedback is given in a subsequent &lt;b&gt;Inspection meeting&lt;/b&gt;. The author fixes any defects identified and the reviewers verify that the defects are fixed in a further &lt;b&gt;Verification meeting&lt;/b&gt;. &lt;/p&gt;  &lt;p&gt;Formal inspections are extremely thorough and effective at finding defects in code but take a long time to complete. &lt;/p&gt;  &lt;h5&gt;Lightweight Code Review&lt;/h5&gt;  &lt;p&gt;Lightweight code review typically requires less overhead than formal code inspections. However, if done properly, it can be equally effective.&amp;#160; Lightweight reviews are often conducted as part of the normal software development process and attempt to improve the cost-benefit factor – providing improved code quality without incurring the overhead of traditional meetings-based inspections [Wikipedia01] [Cohen01]: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Over-the-shoulder review&lt;/strong&gt; – One developer standing over the author’s workstation while the author walks the reviewer through a set of code changes. Simple to execute, these kinds of reviews lend themselves to learning and sharing between developers and gets people interacting with each other instead of hiding behind impersonal e-mail and instant messages. The informality and simplicity unfortunately also leads to some shortcomings such as the process not being enforceable; lack of code review process metrics; does not work for distributed teams; the reviewer being led too hastily through the code and the reviewer not verifying that defects were fixed properly. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Email pass-around&lt;/strong&gt; – The author or source code management system packages the code changes and sends an e-mail to the reviewers. Relatively simple to execute, these kinds of reviews have the added benefit of working equally well with distributed teams. Other people, like domain experts, can also be brought in to review certain areas or a reviewer may even defer to another reviewer. Some shortcomings include the difficulty to track the various threads of conversation or code changes; lack of code review process metrics and the reviewers not being able to verify that defects were fixed properly. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Tool-assisted reviews&lt;/strong&gt; – Specialized tools are used in all aspects of the review such as collecting files, transmitting and displaying files, commentary, collecting metrics and controlling the code review process workflow. The major drawback of any tool-assisted review is the cost of buying a commercial offering or the development cost associated with developing an in-house tool. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Pair Programming&lt;/strong&gt; – Two developers write code together at a single workstation using continuous free-form discussion and review such as is common in &lt;a href="http://en.wikipedia.org/wiki/Extreme_Programming"&gt;Extreme Programming&lt;/a&gt;. Some people argue in favour of the deep insight the reviewer has into the problem at hand, whilst other argue that the closeness is exactly what you do not want from a reviewer as you want a fresh, unbiased opinion. Some people suggest doing both pair programming and a follow-up standard review using a fresh pair of eyes. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;In a current project that I am working on, we are using the over-the-shoulder kind of review process.&amp;#160; Rather than doing no review, we opted for using this approach as the best way to balance the cost-benefit factor of our reviews.&amp;#160; Every submission into the repository needs to be reviewed by a fellow developer.&amp;#160; The details of the reviewer is added to the check-in note to provide the necessary traceability and visibility.&amp;#160; Authors rotate the developers doing the reviews based on the area of the system changed and also to do some cross-skilling.&amp;#160; &lt;/p&gt;  &lt;p&gt;From our experience, we also find the informality of the process as its biggest downfall.&amp;#160; As pressure starts to build, less time is spend on doing reviews and the process sometimes gets perilously close to becoming a mere formality.&lt;/p&gt;  &lt;h2&gt;Review Metrics&lt;/h2&gt;  &lt;p&gt;The following metrics are typically used to measure the effectiveness of a code review process: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;b&gt;Inspection Rate&lt;/b&gt;: How fast are we able to review code? Normally measured in kLOC (thousand Lines Of Code) per man-hour. &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Defect Rate&lt;/b&gt;: How fast are we able to find defects? Normally measured in number of defects found per man-hour. &lt;/li&gt;    &lt;li&gt;&lt;b&gt;Defect Density&lt;/b&gt;: How many defects do we find in a given amount of code? Normally measured in number of defects found per kLOC.&amp;#160; The higher the defect density, the more defects are being identified which usually implies a more effective review process. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;This begs the question, what are good values for these metrics?&amp;#160; [Cohen01] uses two examples to illustrate the difficulties with evaluating these metrics:&amp;#160; &lt;/p&gt;  &lt;p&gt;In Example A a few lines of code to a mission critical module are evaluated by 3 reviewers to absolutely ensure that no defects are introduced.&amp;#160; The review results in a high defect density (say 4 defects in a few lines), slow inspection rate and a defect rate of 1 defect per hour.&amp;#160; In Example B changes made to a GUI dialog box results in 120&amp;#160; lines of changed code, of which some of the code was generated by the GUI designer.&amp;#160; One reviewer is assigned to verify the changes and the reviewer chooses to ignore the designer generated code and only evaluates the code behind the GUI elements added.&amp;#160; This results in a low defect density (say 1 bug in 120 lines), fast inspection rate (say 30 minutes) and a defect rate of 2 defects per hour.&lt;/p&gt;  &lt;p&gt;As evident, the metrics are quite different. Should the high defect density rate of Example A reflect badly on the developer? [Cohen01] argues probably not as the high defect density is the result of the multiple reviewers scrutinizing every line of code to make absolutely sure no defects are introduced.&amp;#160; Should the low defect density rate of Example B reflect badly on the reviewer?&amp;#160; [Cohen01] argues probably not as it is difficult to review designer generated code.&amp;#160; As the code is also not mission critical like in Example A, the reviewer was perhaps intentionally tasked to spend less time reviewing the changes.&lt;/p&gt;  &lt;h2&gt;Review Frequency&lt;/h2&gt;  &lt;p&gt;There are no hard and fast rules for determining the frequency of code reviews. The frequency of code reviews can be influenced by quite a few factors and has to be determined contextually. Some of the factors to consider include: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Review type: Formal Code Review requires more time and effort to complete than Lightweight Code Review. &lt;/li&gt;    &lt;li&gt;Review purpose: Code reviews used to mentor and improve team collaboration might need to be executed more frequently. &lt;/li&gt;    &lt;li&gt;Frequency and scope of code changes: Frequent, small check-ins versus irregular, big check-ins. &lt;/li&gt;    &lt;li&gt;Nature of the development effort: Open Source; Onshore; Offshore. &lt;/li&gt;    &lt;li&gt;Business need for quality: Mission critical applications need to ensure a high level of quality. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Having said of all this, doing infrequent code reviews or waiting to do reviews till code complete seriously undermines the benefit and integrity of the code review process. Reviewing code frequently motivates the developers to ensure the quality of the code being delivered – better known as the &lt;a href="http://en.wikipedia.org/wiki/Hawthorne_effect"&gt;Hawthorne Effect&lt;/a&gt; [Wikipedia02]. &lt;/p&gt;  &lt;h2&gt;Best Practices for Peer Code Review&lt;/h2&gt;  &lt;p&gt;[Cohen02] and [Bogue] present several techniques to ensure that your code reviews improve your code without wasting your developer’s time: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Verify that defects are actually fixed! &lt;/li&gt;    &lt;li&gt;Remember the purpose: Code reviews often start off on the wrong foot because they are perceived as an unnecessary step that has been forced upon the developers or, in some cases evidence that management doesn’t trust the developers. Code reviews are a proven, effective way to minimize defects and they are, at their core, an industry best practice. &lt;/li&gt;    &lt;li&gt;A matter of approach: Prevent code reviews from becoming mental jousting matches where people take shots at each other. Consider the review process as a forum to collaborate and learn from one another. Reviewers should ask questions rather than making statements; remember to praise and also be mindful of the fact that there is often more than one way to approach a solution. Authors should try to hear past attacking comments and try to focus on the learning that they can get out of the process. &lt;/li&gt;    &lt;li&gt;Review fewer than 200-400 lines of code at a time and aim for an inspection rate of less than 300-500 LOC/hour: Take your time when doing a review - faster is not better. &lt;/li&gt;    &lt;li&gt;Never review for more than 60-90 minutes at a time.&amp;#160; &lt;/li&gt;    &lt;li&gt;Authors should consider how to best explain their changes before the review begins: [Cohen02] refers to this process as “annotating the source code”. As the author has to re-think and explain the changes during the annotation process, the author will uncover many defects before the review even begins. &lt;/li&gt;    &lt;li&gt;Checklists substantially improve results for both authors and reviewers: Omissions are the hardest defects to find. A checklist is a great way to avoid this problem as it reminds the reviewer or author to take the time to look for something that might be missing. Publish the checklists on a wiki. As each person typically makes the same 15-20 mistakes, also consider creating personal checklists. &lt;/li&gt;    &lt;li&gt;Management must foster a good code review culture in which finding defects is viewed positively: A negative attitude towards defects found can sour a whole team and sabotage the bug-finding process. &lt;/li&gt;    &lt;li&gt;Beware of the “Big Brother” effect: Code review metrics should never be used to single out developers, particularly not in front of their peers. Metrics should be used to measure the efficiency or the effect of the process. &lt;/li&gt;    &lt;li&gt;The Ego Effect: Do at least some code review, even if you don’t have time to review it all. The Ego effect drives developers to review their own work and write better code because they know others will be looking at their code. &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;&amp;#160;&lt;/h2&gt;  &lt;h2&gt;Tools&lt;/h2&gt;  &lt;p&gt;I found the following tools to support a lightweight, tool-assisted peer code review process: &lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;a href="http://www.smartbear.com/codecollab.php"&gt;Code Collaborator&lt;/a&gt; - Commercial offering from &lt;a href="http://www.smartbear.com/"&gt;Smart Bear Software&lt;/a&gt; that supports online reviews with inline source commenting, threaded contextual chat, asynchronous reviews for when participants are separated by many timezones, review metrics and reports, version control integration, customisable workflow and &lt;a href="http://smartbearsoftware.com/codecollab-features.php"&gt;much more&lt;/a&gt;. &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.atlassian.com/software/crucible/"&gt;Crucible&lt;/a&gt; - Commercial offering from &lt;a href="http://www.atlassian.com/"&gt;Atlassian&lt;/a&gt; that supports online reviews with inline source commenting, threaded comments, review metrics, version control integration, workflow and &lt;a href="http://www.atlassian.com/software/crucible/features/"&gt;much more&lt;/a&gt;. &lt;/li&gt;    &lt;li&gt;&lt;a href="http://codestriker.sourceforge.net/"&gt;Codestriker&lt;/a&gt; - Open source project that supports online reviews with version control integration and review metrics. &lt;/li&gt; &lt;/ol&gt;  &lt;h2&gt;Conclusion&lt;/h2&gt;  &lt;p&gt;Well that about covers my thoughts on the topic.&amp;#160; I'm interested to know how many people are actually doing some form of peer code review.&amp;#160; What type of reviews are you doing?&amp;#160; How often do you do reviews? Do you use any tools to assist you with your reviews?&amp;#160; What code review practices work best in your environment?&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-3315957687821968027?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/_ClGtwj7coE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/3315957687821968027/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2009/11/code-reviews.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/3315957687821968027?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/3315957687821968027?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/_ClGtwj7coE/code-reviews.html" title="Code Reviews" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2009/11/code-reviews.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEMGRns_eCp7ImA9Wx5QFkQ.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-5749519246118577828</id><published>2009-11-01T20:55:00.001+02:00</published><updated>2010-09-05T15:13:47.540+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-05T15:13:47.540+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="CodeAnalysis" /><category scheme="http://www.blogger.com/atom/ns#" term="FxCop" /><title>FxCop</title><content type="html">&lt;strong&gt;NOTE: This is a repost of on old post as &lt;a href="http://fromthedevtrenches.blogspot.com/2009/10/migrating-blog-onto-blogger.html"&gt;I am moving&lt;/a&gt; onto the Blogger platform&lt;/strong&gt;   &lt;br /&gt;  &lt;br /&gt;&lt;strong&gt;&lt;img style="border-bottom: 0px; border-left: 0px; margin: 0px 10px 0px 0px; display: inline; border-top: 0px; border-right: 0px" title="Traffic light" border="0" alt="Traffic light" align="left" src="http://lh4.ggpht.com/_ziqU4IJY4Uc/TIOXGevHJpI/AAAAAAAAAtk/0unPjriPqjg/Traffic%20light%5B7%5D.jpg?imgmax=800" width="103" height="115" /&gt;&lt;/strong&gt;In previous posts about &lt;a href="http://dotnet.org.za/cjlotz/archive/2007/01/02/Code-Metrics.aspx"&gt;Code Metrics&lt;/a&gt; and &lt;a href="http://dotnet.org.za/cjlotz/archive/2007/08/28/code-reviews.aspx"&gt;Code Reviews&lt;/a&gt;, I explored some metrics and techniques that I felt should form part of any good software quality control process.&amp;#160; One of the tools that I mentioned is FxCop.&amp;#160; In this post I take a closer look at FxCop.&amp;#160; I start by looking at how FxCop works and how you can fit it into your development process.&amp;#160; I then consider the different rule sets to use and look at how you can utilise FxCop to guide your VS 2003/2005/2008 development efforts.&amp;#160; I finish off the article by linking to articles that show you how to develop your own custom FxCop rules.   &lt;a name='more'&gt;&lt;/a&gt;  &lt;br /&gt;  &lt;h4&gt;&amp;#160;&lt;/h4&gt;  &lt;h2&gt;Introduction&lt;/h2&gt;  &lt;p&gt;FxCop analyses .NET assemblies for potential code compliance problems and forms part of &lt;a href="http://en.wikipedia.org/wiki/Static_code_analysis"&gt;static code analysis&lt;/a&gt;. With static code analysis the compiled code is checked for compliance to identify possible defects before executing the code.&amp;#160; FxCop employs assembly analysis of generated assemblies using an introspection engine. Since the analysis is performed on the generated intermediate language (&lt;a href="http://en.wikipedia.org/wiki/MSIL"&gt;MSIL&lt;/a&gt;) code, FxCop is not dependent on any particular .NET implementation language.&amp;#160; However, it is important to remember that assembly analysis cannot analyse certain aspects of the original source code, such as code comments, since these are not carried over in the compilation process.&amp;#160;&amp;#160; You may also run into a scenarios where there are differences between the FxCop violations in Debug and Release configurations due to the compiler optimisations being applied in Release mode.&amp;#160; &lt;/p&gt;  &lt;p&gt;FxCop ships with a large rule set analysing library design, globalization, interoperability, maintainability, mobility, naming, performance, portability, reliability, security and usage aspects of the assembly. The rule set can be extended to include new custom rules and existing rules can be switched off if necessary. &lt;/p&gt;  &lt;h2&gt;Process&lt;/h2&gt; FxCop will typically be used by the following people:   &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;Developers use FxCop continuously during development, because it helps with familiarising themselves with the .NET coding best practices. As they progress they should find that they break fewer rules and can consequently rely on the tool less often. However, they should still continue to evaluate their code at predefined intervals in the SDLC. By actively using this tool, developers raise the standard of code going into code review sessions. I advocate for using the tool before every commit. &lt;/li&gt;    &lt;li&gt;Code reviewers use the tool to verify that developers are indeed complying with the best practices as defined in the rule set. They should also check that they agree with any &amp;quot;excluded&amp;quot; defects. Use of FxCop should rapidly improve both the speed and breadth of code review sessions by instantly highlighting the most obvious problems. &lt;/li&gt; &lt;/ul&gt; I &lt;strong&gt;strongly&lt;/strong&gt; recommend using FxCop together with a refactoring tool like &lt;a href="http://www.jetbrains.com/resharper/"&gt;ReSharper&lt;/a&gt; which makes fixing the rule violations a lot easier and less error prone.   &lt;br /&gt;  &lt;h2&gt;&amp;#160;&lt;/h2&gt;  &lt;h2&gt;FxCop Backlogs&lt;/h2&gt; The following articles present some ideas on how to introduce FxCop into your SDLC:   &lt;br /&gt;  &lt;ol&gt;   &lt;li&gt;&lt;a href="http://msmvps.com/blogs/calinoiu/archive/2007/04/22/fxcop-and-the-big-bad-backlog.aspx"&gt;FxCop and the big-bad-backlog&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://msmvps.com/blogs/calinoiu/archive/2007/04/29/fxcop-backlogs-some-rules-for-rule-activation.aspx"&gt;FxCop backlogs: Some rules for rule activation&lt;/a&gt; &lt;/li&gt; &lt;/ol&gt;  &lt;h2&gt;Rule sets&lt;/h2&gt; The rule sets provided with FxCop are quite extensive.&amp;#160; Some rule sets (i.e Globalization/Mobility rule set) also includes rules that only apply to applications that target certain platforms/cultures/languages etc. Microsoft itself uses &lt;a href="http://blogs.msdn.com/fxcop/archive/2007/08/09/what-rules-do-microsoft-have-turned-on-internally.aspx"&gt;a sub-set&lt;/a&gt; of the complete FxCop rules to guide their own internal development efforts. From experience, I have created two rule sets to guide my own development efforts.   &lt;br /&gt;  &lt;h5&gt;Base Rule Set&lt;/h5&gt; The Base Rule Set is the rule set that I use for all &lt;strong&gt;new&lt;/strong&gt; .NET development efforts. This rule set &lt;strong&gt;excludes&lt;/strong&gt; the following rules:   &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Globalization Rules:&lt;/strong&gt; CA1300: Specify MessageBoxOptions &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Globalization Rules:&lt;/strong&gt; CA1301: Avoid duplicate accelerators &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Globalization Rules:&lt;/strong&gt; CA1302: Do not hardcode locale specific strings &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Globalization Rules&lt;sup&gt;+&lt;/sup&gt;:&lt;/strong&gt; CA1303: Do not pass literals as localized parameters &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Naming Rules: CA1701:&lt;/strong&gt; Resource string compound words should be cased correctly &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Naming Rules: CA1702:&lt;/strong&gt; Compound words should be cased correctly &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Naming Rules: CA1703:&lt;/strong&gt; Resource strings should be spelled correctly &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Naming Rules: CA1704:&lt;/strong&gt; Identifiers should be spelled correctly &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Naming Rules: CA1726:&lt;/strong&gt; Use preferred terms &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Usage Rules: CA2204&lt;sup&gt;+&lt;/sup&gt;:&lt;/strong&gt; Literals should be spelled correctly &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Usage Rules: CA2243:&lt;/strong&gt; Attribute string literals should parse correctly &lt;/li&gt; &lt;/ul&gt; &lt;strong&gt;&lt;sub&gt;+ Not available in VS 2008&lt;/sub&gt;&lt;/strong&gt;   &lt;br /&gt;  &lt;h5&gt;Minimum Rule Set&lt;/h5&gt; The Minimum Rule Set is the rule set that I use for all &lt;strong&gt;existing&lt;/strong&gt; .NET development efforts. The idea is that these projects will most likely hit more rule violations on their existing code base and I therefore want to exclude some rules that add a lot of noise without providing IMO a lot of benefit. &lt;strong&gt;This rule set adds the following &lt;em&gt;additional&lt;/em&gt; exclusions to those already excluded within the Base Rule Set:&lt;/strong&gt;   &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Design Rules:&lt;/strong&gt; CA1002: Do not expose generic lists &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Design Rules:&lt;/strong&gt; CA1003: Use generic event handler instances &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Design Rules:&lt;/strong&gt; CA1004: Generic method should provide type parameter &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Design Rules:&lt;/strong&gt; CA1005: Avoid excessive parameters on generic types &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Design Rules:&lt;/strong&gt; CA1007: Use generics where appropriate &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Design Rules:&lt;/strong&gt; CA1010: Collections should implement generic interface &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Design Rules:&lt;/strong&gt; CA1020: Use properties where appropriate &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Design Rules:&lt;/strong&gt; CA1024: Avoid namespaces with few types &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Design Rules:&lt;/strong&gt; CA1031: Do not catch general exception types &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Design Rules:&lt;/strong&gt; CA1064: Exceptions should be public &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Globalization Rules:&lt;/strong&gt; CA1304: Specify CultureInfo &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Globalization Rules:&lt;/strong&gt; CA1305: Specify IFormatProvider &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Globalization Rules:&lt;/strong&gt; CA1306: Set locale for data types &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Naming Rules:&lt;/strong&gt; CA1705&lt;sup&gt;+&lt;/sup&gt;: Long acronyms should be pascal-cased &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Naming Rules:&lt;/strong&gt; CA1706&lt;sup&gt;+&lt;/sup&gt;: Short acronyms should be uppercase &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Naming Rules:&lt;/strong&gt; CA1707: Identifiers should not contain underscores &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Naming Rules:&lt;/strong&gt; CA1713: Events should not have before or after prefix &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Naming Rules:&lt;/strong&gt; CA1714: Flags enums should have plural names &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Naming Rules:&lt;/strong&gt; CA1717: Only FlagsAttribute enums should have plural names &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Mobility Rules:&lt;/strong&gt; CA1600: Do not use idle process priority &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Mobility Rules:&lt;/strong&gt; CA1601: Do not use timers that prevent power state changes &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Performance Rules:&lt;/strong&gt; CA1800: Do not cast unnecessary &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Performance Rules:&lt;/strong&gt; CA1802: Use literals where appropriate &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Performance Rules:&lt;/strong&gt; CA1805: Do not initialize unnecessary &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Performance Rules:&lt;/strong&gt; CA1822: Mark members as static &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Usage Rules:&lt;/strong&gt; CA2201: Do not raise reserved exception types &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Usage Rules:&lt;/strong&gt; CA2205: Use managed equivalent of win32 api &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Usage Rules:&lt;/strong&gt; CA2225: Operator overloads have named alternates &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Usage Rules:&lt;/strong&gt; CA2242: Test for NaN correctly &lt;/li&gt; &lt;/ul&gt; &lt;strong&gt;&lt;sub&gt;+ Not available in VS 2008&lt;/sub&gt;&lt;/strong&gt;   &lt;br /&gt;  &lt;h4&gt;&amp;#160;&lt;/h4&gt;  &lt;h2&gt;Implementation&lt;/h2&gt; There are differences between using FxCop for Visual Studio 2003 and Visual Studio 2005/2008 development. For projects that have been upgraded from VS 2003 to VS 2005, read the &lt;a href="http://blogs.msdn.com/fxcop/archive/2006/05/19/making-it-easier-to-move-from-fxcop-to-visual-studio-code-analysis-jeffrey-van-gogh.aspx"&gt;following article&lt;/a&gt; for tips on how to migrate your existing VS 2003 FxCop exclusions file over to VS 2005 FxCop code exclusions.   &lt;br /&gt;  &lt;h5&gt;VS 2003&lt;/h5&gt; Obtain FxCop from &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=3389f7e4-0e55-4a4d-bc74-4aeabb17997b&amp;amp;displaylang=en"&gt;here&lt;/a&gt;. Analyses can be performed from either using the FxCop GUI directly or from the FxCop command-line utility which allows you to integrate into a &lt;a href="http://dotnet.org.za/cjlotz/archive/2007/12/03/continuous-integration-from-theory-to-practice.aspx"&gt;continuous integration process&lt;/a&gt;.   &lt;br /&gt;  &lt;h5&gt;VS 2005&lt;/h5&gt; VS 2005 adds static code analysis through integrating FxCop directly into the IDE. A developer can select to include static code analysis as part of the compilation process which will fire off FxCop and produce a list of errors/warnings in the Error list pane that prevents the code from compiling successfully. &lt;a href="http://msdn2.microsoft.com/en-us/library/ms182075%28VS.90%29.aspx"&gt;Code Analysis Policy&lt;/a&gt; for VS Team System can also be created that makes this code analysis process a compulsory step within the compilation process. This will prevent developers from skipping the static code analysis process.   &lt;br /&gt;  &lt;h5&gt;VS 2008&lt;/h5&gt; VS 2008 expands and improves on the code analysis provided in the VS 2005 IDE. Some of the improvements made are:   &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://blogs.msdn.com/fxcop/archive/2006/12/21/two-new-features-for-orcas.aspx"&gt;Ability to exclude generated code from code analysis&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/fxcop/archive/2007/08/08/_24002800_CodeAnalysisTreatWarningAsErrors_2900_-MSBuild-property.aspx"&gt;Single MSBuild property to treat all violations as errors&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/fxcop/archive/2007/08/12/new-for-visual-studio-2008-spelling-rules.aspx"&gt;Inclusion of the FxCop standalone spelling rules&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/fxcop/archive/2007/08/20/new-for-visual-studio-2008-custom-dictionaries.aspx"&gt;Support for custom dictionaries to support the spelling rules&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/fxcop/archive/2007/09/20/new-for-visual-studio-2008-code-analysis-policy-improvements.aspx"&gt;Improvements to Code Analysis Policy&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/fxcop/archive/2007/09/21/new-for-visual-studio-2008-support-for-anonymous-methods-and-lambda-expressions.aspx"&gt;Support for Anonymous Methods and Lamda Expressions&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/fxcop/archive/2007/11/15/code-metrics-as-check-in-policy.aspx"&gt;Ability to Use Code Metrics as Check-in Policy&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt; Also be sure to check out the &lt;a href="http://blogs.msdn.com/kcwalina/archive/2007/10/02/Multi_2D00_TargetingAndFxCop.aspx"&gt;custom FxCop rule&lt;/a&gt; to support the multi-targeting feature of VS 2008.   &lt;br /&gt;  &lt;h4&gt;&amp;#160;&lt;/h4&gt;  &lt;h2&gt;Continuous Integration&lt;/h2&gt; FxCop can easily be integrated into a &lt;a href="http://fromthedevtrenches.blogspot.com/2009/11/continuous-integration-from-theory-to_01.html"&gt;continuous integration&lt;/a&gt; process by using the standalone FxCop command-line utility for VS 2003 or by using VS 2005/2008 Code Analysis.&amp;#160; As already mentioned, development teams using Visual Studio Team System can include &lt;a href="http://msdn2.microsoft.com/en-us/library/ms182075%28VS.90%29.aspx"&gt;Code Analysis Policy&lt;/a&gt; to enforce the continuous use of FxCop in their development environments.   &lt;br /&gt;  &lt;h4&gt;&amp;#160;&lt;/h4&gt;  &lt;h2&gt;Custom rule development&lt;/h2&gt; It is possible to write your own rules to integrate with FxCop running standalone or integrated into the VS IDE. Here are some articles on the topic:   &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://blogs.interknowlogy.com/timmccarthy/archive/2007/02/13/11543.aspx"&gt;How to write custom code analysis rules for VS 2005&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://bordecal.mvps.org/Nicole/FxCop/CustomRulesSample.htm"&gt;Custom rule sample&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://blogs.msdn.com/fxcop/archive/2007/05/16/faq-how-do-i-debug-a-custom-rule.aspx"&gt;How to debug a custom rule&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://msmvps.com/blogs/calinoiu/archive/2007/04/21/no-rules-in-your-fxcop-rule-assembly.aspx"&gt;No rules in your FxCop assembly&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;&amp;#160;&lt;/h2&gt;  &lt;h2&gt;Further reading&lt;/h2&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://blogs.msdn.com/fxcop/"&gt;Code Analysis and Code Metrics&lt;/a&gt; - The Visual Studio Code Analysis Team &lt;/li&gt;    &lt;li&gt;&lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconnetframeworkdesignguidelines.asp"&gt;Design Guidelines for Class Library Developers&lt;/a&gt; - The FxCop rules are largely based on the guidelines contained in this document &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.amazon.com/Framework-Design-Guidelines-Conventions-Development/dp/0321246756/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1198227102&amp;amp;sr=8-1"&gt;Framework Design Guidelines&lt;/a&gt; by Krzysztof Cwalina and Brad Abrams &lt;/li&gt; &lt;/ul&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-5749519246118577828?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/DUIOAhubP-c" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/5749519246118577828/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2009/11/fxcop.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/5749519246118577828?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/5749519246118577828?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/DUIOAhubP-c/fxcop.html" title="FxCop" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh4.ggpht.com/_ziqU4IJY4Uc/TIOXGevHJpI/AAAAAAAAAtk/0unPjriPqjg/s72-c/Traffic%20light%5B7%5D.jpg?imgmax=800" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2009/11/fxcop.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkQGQn05cCp7ImA9Wx5QFkQ.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-6109644880957140797</id><published>2009-11-01T20:53:00.001+02:00</published><updated>2010-09-05T14:38:43.328+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-05T14:38:43.328+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="DotNET" /><category scheme="http://www.blogger.com/atom/ns#" term="ContinuousIntegration" /><title>Continuous Integration in .NET: From Theory to Practice</title><content type="html">&lt;strong&gt;NOTE: This is a repost of on old post as &lt;a href="http://fromthedevtrenches.blogspot.com/2009/10/migrating-blog-onto-blogger.html"&gt;I am moving&lt;/a&gt; onto the Blogger platform&lt;/strong&gt;   &lt;br /&gt;  &lt;br /&gt;&lt;img style="border-bottom: 0px; border-left: 0px; margin: 0px 15px 0px 0px; display: inline; border-top: 0px; border-right: 0px" title="TeamPuzzle" border="0" alt="TeamPuzzle" align="left" src="http://lh3.ggpht.com/_ziqU4IJY4Uc/TIOPUMvHs7I/AAAAAAAAAtU/JjC7IHmhz_g/TeamPuzzle%5B6%5D.jpg?imgmax=800" width="138" height="138" /&gt; &lt;a href="http://www.martinfowler.com/articles/continuousIntegration.html"&gt;Continuous Integration&lt;/a&gt; (CI) is a popular incremental integration process whereby each change made to the system is integrated into a latest build. These integration points can occur continuously on every commit to the repository or on regular intervals like every 30 minutes.&amp;#160; They should however not take longer than a day i.e. you need to integrate at least once daily.&amp;#160; In this article I take a closer look at CI.&amp;#160; The article is divided into two main sections: theory and practice.&amp;#160; In the &lt;em&gt;theory&lt;/em&gt; section, I consider some CI best practices; look at the benefits of integrating frequently and reflect on some recommendations for introducing CI into your environment.&amp;#160; The &lt;em&gt;practice&lt;/em&gt; section provides an in-depth example of how to implement a CI process using .NET development tooling.&amp;#160; I conclude the article by providing some additional, recommended reading.   &lt;br /&gt;  &lt;h2&gt;&amp;#160;&lt;/h2&gt;  &lt;h2&gt;References&lt;/h2&gt; I used the following references in creating the article:   &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;[McConnell] &lt;a href="http://www.cc2e.com/Default.aspx"&gt;&lt;em&gt;Code Complete, 2nd Edition&lt;/em&gt;&lt;/a&gt;&lt;em&gt; &lt;/em&gt;by Steve McConnell. &lt;/li&gt;    &lt;li&gt;[Fowler] &lt;a href="http://martinfowler.com/articles/continuousIntegration.html"&gt;&lt;em&gt;Continuous Integration&lt;/em&gt;&lt;/a&gt;&lt;em&gt; &lt;/em&gt;by Martin Fowler. &lt;/li&gt;    &lt;li&gt;[Miller] &lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2005/07/25/129797.aspx"&gt;&lt;em&gt;Using Continuous Integration?&amp;#160; Better do the &amp;quot;Check In Dance&amp;quot;&lt;/em&gt;&lt;/a&gt; by Jeremy Miller. &lt;/li&gt;    &lt;li&gt;[Elssamadisy] &lt;em&gt;&lt;a href="http://www.infoq.com/minibooks/agile-patterns"&gt;Patterns of Agile Practice Adoption: The Technical Cluster&lt;/a&gt;&lt;/em&gt; by Amr Elssamadisy. &lt;/li&gt;    &lt;li&gt;[Duvall] &lt;a href="http://www.ibm.com/developerworks/java/library/j-ap11297/index.html"&gt;&lt;em&gt;Continuous Integration Anti-Patterns&lt;/em&gt;&lt;/a&gt; by Paul Duvall. &lt;/li&gt; &lt;/ul&gt; &lt;a name='more'&gt;&lt;/a&gt;  &lt;h2&gt;&amp;#160;&lt;/h2&gt;  &lt;h2&gt;Practices&lt;/h2&gt; Martin Fowler presents the following set of practices for CI [Fowler]:   &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Maintain a single source repository&lt;/strong&gt; - Use a decent source code management system and make sure its location is well known as the place where everyone can go to get source code.&amp;#160; Also ensure that everything is put into the repository (test scripts, database schema, third party libraries etc.) &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Automate the build&lt;/strong&gt; - Make sure you can build and launch your system using MSBuild/NAnt scripts in a single command.&amp;#160; Include everything into your build.&amp;#160; As a simple rule of thumb: anyone should be able to bring in a clean machine, check the sources out of the repository and issue a single command to have a running system on their machine. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Make your build self-testing&lt;/strong&gt; - Include automated tests in your build process.&amp;#160; &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Everyone commits every day&lt;/strong&gt; - &amp;quot;&lt;em&gt;A commit a day keeps the integration woes away&amp;quot;&lt;/em&gt; [Duvall].&amp;#160; Frequent commits encourage developers to break down their work into small chunks of a few hours each. Before committing their code, they need to update their working copy with the &lt;a href="http://www.scmpatterns.com/book/pattern-summary.html"&gt;mainline&lt;/a&gt;, resolve any conflicts and ensure that everything still works fine.&amp;#160; Jeremy Miller refers to this process as the &amp;quot;Check In Dance&amp;quot; [Miller]. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Every commit should build the mainline on an integration machine&lt;/strong&gt; - Use a CI server like or &lt;a href="http://ccnet.thoughtworks.com/"&gt;CruiseControl.NET&lt;/a&gt; or &lt;a href="http://msdn2.microsoft.com/en-us/library/ms181710%28VS.90%29.aspx"&gt;Team Foundation Build&lt;/a&gt;.&amp;#160; If the mainline build fails, it needs to be fixed right away. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Keep the build fast&lt;/strong&gt; - If the build takes too long to execute, try and create a staged build/build pipeline where multiple builds are done in a sequence.&amp;#160; The first build (aka &lt;em&gt;''commit build''&lt;/em&gt;) executes quickly and gives other people confidence that they can work with the code in the repository.&amp;#160; Further builds can run additional, slower running unit tests, create code metrics, check the code against coding standards, create documentation etc. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Test in a clone of the production environment&lt;/strong&gt; - Try to set up your test environment to be as exact a mimic of your production environment as possible.&amp;#160; Use the same versions of third party software, the same operating system version etc.&amp;#160;&amp;#160; Consider using virtualization to make it easy to put together test environments. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Make it easy for anyone to get the latest executable&lt;/strong&gt; - Make sure that there is a well known place where people can find the latest executable. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Everyone can see what's happening&lt;/strong&gt; - Make the state of the mainline build as visible as possible. Use various feedback mechanisms to relate build status information [Duvall].&amp;#160; Some fun examples include using &lt;a href="http://www.pragmaticautomation.com/cgi-bin/pragauto.cgi/Monitor/Devices/BubbleBubbleBuildsInTrouble.rdoc"&gt;lava lamps&lt;/a&gt;, &lt;a href="http://www.hamang.net/index.php?option=com_content&amp;amp;task=view&amp;amp;id=16&amp;amp;Itemid=9"&gt;a big screen LCD&lt;/a&gt; and &lt;a href="http://blogs.msdn.com/mswanson/articles/169058.aspx"&gt;an ambient orb&lt;/a&gt;. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Automate deployment&lt;/strong&gt; - Have scripts that allow you to automatically deploy into different environments, including production.&amp;#160; For web applications, consider deploying a trial build to a subset of users before deploying to the full user base. &lt;/li&gt; &lt;/ul&gt; Jeremy Miller adds the following advice [Miller]:   &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Check in as often as you can - &lt;/strong&gt;Try breaking down your workload into meaningful chunks of code and integrate these pieces of code when you have a collection of code in a consistent state. Checking in once a week seriously compromises the effectiveness of a CI process. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Don't leave the build broken overnight&lt;/strong&gt; - Developers need to be immediately notified upon a build breakage and make it a top priority to fix a broken build. &lt;/li&gt;    &lt;li&gt;Don't ever check into a busted build. &lt;/li&gt;    &lt;li&gt;If you are working on fixing the build, let the rest of the team know. &lt;/li&gt;    &lt;li&gt;Every developer needs to know how to execute a build locally and troubleshoot a broken build. &lt;/li&gt; &lt;/ul&gt; Paul Duvall also warns against some additional CI anti-patterns that tend to produce adverse effects [Duvall]. The ones that have not been covered above are:   &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;The cold shoulder of spam feedback&lt;/strong&gt; - Team members sometimes quickly become inundated with build status e-mails (success and failure and everything in between) to the point where they start to ignore messages. Try to make the feedback succinctly targeted so that people don't receive irrelevant information. &lt;/li&gt;    &lt;li&gt;D&lt;strong&gt;on't delay feedback with a slow machine&lt;/strong&gt; - Get a build machine that has optimal disk speed, processor, and RAM resources for speedy builds. &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;&amp;#160;&lt;/h4&gt;  &lt;h2&gt;Benefits&lt;/h2&gt; Numerous benefits result from integrating continuously [McConnell]:   &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Errors are easier to locate&lt;/strong&gt; - New problems can be narrowed down to the small part that was recently integrated. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Improved team morale&lt;/strong&gt; - Programmers see early results from their work. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Better customer relations&lt;/strong&gt; - Customers like signs of progress and incremental builds provide signs of progress frequently. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;More reliable schedule estimates &amp;amp; more accurate status reporting&lt;/strong&gt; - Management gets a better sense of progress than the typical &amp;quot;&lt;em&gt;coding is 99% percent complete&amp;quot;&lt;/em&gt; message. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Units of the system are tested more fully&lt;/strong&gt; - As integration starts early in the project the code is exercised as part of the overall system more frequently. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Work that sometimes surfaces unexpectedly at the end of a project&lt;/strong&gt; &lt;strong&gt;is exposed early on&lt;/strong&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;&amp;#160;&lt;/h4&gt;  &lt;h2&gt;Where do I start?&lt;/h2&gt; Here are some steps to consider for introducing a CI process [Fowler]:   &lt;br /&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;Get the build automated&lt;/strong&gt; - Get everything into source control and make sure you can build the whole system with a single command. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Introduce automated testing in the build&lt;/strong&gt; - Identify major areas where things go wrong and start adding automated tests to expose these failures. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Speed up the build&lt;/strong&gt; - Try aiming at creating a build that runs to completion within ten minutes.&amp;#160; Constantly monitor your build and take action as soon as your start going slower than the ten minute rule. &lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Start all new projects with CI from the beginning&lt;/strong&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;&amp;#160;&lt;/h4&gt;  &lt;h2&gt;.NET Implementation &amp;amp; Tools&lt;/h2&gt; I have written a &lt;a href="http://fromthedevtrenches.blogspot.com/2009/11/continuous-integration-from-theory-to.html"&gt;set of articles&lt;/a&gt; that describe a complete setup of a .NET CI solution.&amp;#160; The CI process uses a wide variety of tools including CruiseControl.NET, Subversion, MSBuild, Visual Studio 2008, NUnit, FxCop, NCover, WiX and SandCastle.&amp;#160; You can &lt;a href="http://sites.google.com/site/fromthedevtrenches/downloads/ContinuousIntegration-FromTheorytoPractice%2C2ndEd.pdf?attredirects=0&amp;amp;d=1"&gt;download&lt;/a&gt; the series as a fully searchable PDF with PDF bookmarks and PDF links.   &lt;br /&gt;&lt;a href="http://msdn2.microsoft.com/en-us/teamsystem/aa718934.aspx"&gt;Team Foundation Server&lt;/a&gt; users can check out the &lt;a href="http://www.infoq.com/news/2007/08/tfs-2008-continuous-integration"&gt;new and improved out-of-the-box support&lt;/a&gt; for continuous integration provided by Team Foundation Server 2008.&amp;#160; This, coupled with the &lt;a href="http://blogs.msdn.com/bharry/archive/2007/11/23/tfs-licensing-change-for-tfs-2008.aspx"&gt;recent announcement&lt;/a&gt; on the TFS Licensing Change for TFS 2008, makes using Team Foundation Server less expensive and a more viable option to consider.   &lt;br /&gt;  &lt;h4&gt;&amp;#160;&lt;/h4&gt;  &lt;h2&gt;Recommended Reading&lt;/h2&gt;  &lt;ol&gt;   &lt;li&gt;&lt;a href="http://www.amazon.com/Continuous-Integration-Improving-Addison-Wesley-Signature/dp/0321336380/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1196675506&amp;amp;sr=1-1"&gt;Continuous Integration: Improving Software Quality and Reducing Risk&lt;/a&gt; by Paul Duvall. &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.scmpatterns.com/book/"&gt;Software Configuration Management Patterns&lt;/a&gt; by Steve Berczuk and Brad Appleton. &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.amazon.com/exec/obidos/ASIN/0321293533/ambysoftinc"&gt;Refactoring Databases&lt;/a&gt; by Scott Ambler and Pramodkumar Sadalage. &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.amazon.com/gp/product/0321418506/ref=wl_it_dp?ie=UTF8&amp;amp;coliid=I3Q3LC4EPNMYT7&amp;amp;colid=16P4CZJ4SV1K"&gt;Visual Studio Team System: Better Software Development for Agile Teams&lt;/a&gt; by Will Stott and James Newkirk. &lt;/li&gt; &lt;/ol&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-6109644880957140797?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/0cGOwOnc1dA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/6109644880957140797/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2009/11/continuous-integration-from-theory-to_01.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6109644880957140797?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6109644880957140797?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/0cGOwOnc1dA/continuous-integration-from-theory-to_01.html" title="Continuous Integration in .NET: From Theory to Practice" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/_ziqU4IJY4Uc/TIOPUMvHs7I/AAAAAAAAAtU/JjC7IHmhz_g/s72-c/TeamPuzzle%5B6%5D.jpg?imgmax=800" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2009/11/continuous-integration-from-theory-to_01.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkIAQnY-eSp7ImA9Wx5QFkQ.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-6920860119032252962</id><published>2009-11-01T19:27:00.001+02:00</published><updated>2010-09-05T14:42:23.851+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-05T14:42:23.851+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="DotNET" /><category scheme="http://www.blogger.com/atom/ns#" term="ContinuousIntegration" /><title>Continuous Integration in .NET: From Theory to Practice 2nd Edition</title><content type="html">&lt;p&gt;&lt;strong&gt;NOTE: This is a repost of on old post as &lt;a href="http://fromthedevtrenches.blogspot.com/2009/10/migrating-blog-onto-blogger.html"&gt;I am moving&lt;/a&gt; onto the Blogger platform&lt;/strong&gt;    &lt;br /&gt;&lt;strong&gt;     &lt;br /&gt;&lt;/strong&gt;    &lt;br /&gt;&lt;img style="border-bottom: 0px; border-left: 0px; margin: 0px 10px 0px 0px; display: inline; border-top: 0px; border-right: 0px" title="TeamPuzzle" border="0" alt="TeamPuzzle" align="left" src="http://lh6.ggpht.com/_ziqU4IJY4Uc/TIOQLngstyI/AAAAAAAAAtY/jHcvXsJWv68/TeamPuzzle%5B4%5D.jpg?imgmax=800" width="160" height="160" /&gt; During last year I created a guide on implementing &lt;a href="http://fromthedevtrenches.blogspot.com/2009/11/continuous-integration-from-theory-to_01.html"&gt;Continuous Integration&lt;/a&gt; (CI) for a .NET 2.0 development environment.&amp;#160; The guide illustrates how to create a complete CI setup using VS 2005 and MSBuild (no NAnt) together with tools like FxCop, NCover, TypeMock, NUnit, Subversion, InstallShield, QTP, NDepend, Sandcastle and CruiseControl.NET.&amp;#160; The good news is that I spend some time during the last 2 weeks greatly improving the setup for use on a new VS 2008 project and I have decided to release a 2nd Edition of the guide covering the much improved setup.&amp;#160; Instead of creating another series of blog posts to cover the content, I'm releasing the 2nd edition &lt;b&gt;only&lt;/b&gt; as a downloadable PDF guide together with all the associated code and build artefacts.&amp;#160; This will allow new teams to get up and running with CI a lot quicker.&lt;/p&gt;  &lt;p&gt;   &lt;br /&gt;For readers of the first edition of the guide, the most notable differences between the second edition and the first edition of the guide are:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Updated to use VS 2008, .NET 3.5 and MSBuild 3.5 (including new MSBuild features like parallel builds and multi-targeting). &lt;/li&gt;    &lt;li&gt;All tools (NUnit, NDepend, NCover etc.) are now stored in a separate &lt;b&gt;Tools&lt;/b&gt; folder and kept under source control. The only development tools a developer needs to install are VS 2008, SQL Server 2005 and Subversion. The rest of the tools are retrieved form the &lt;a href="http://www.scmpatterns.com/book/pattern-summary.html"&gt;mainline&lt;/a&gt; along with the latest version of the source code. &lt;/li&gt;    &lt;li&gt;Added the CruiseControl.NET configuration (custom style sheets, server setup etc.) to source control and created a &lt;b&gt;single step setup&lt;/b&gt; process for the build server. This &lt;b&gt;greatly&lt;/b&gt; simplifies the process of setting up a new build server. &lt;/li&gt;    &lt;li&gt;Changed from using InstallShield to Windows Installer XML (WiX) for creating a Windows installer (msi). &lt;/li&gt;    &lt;li&gt;Added support for running MbUnit tests in addition to the NUnit tests. &lt;/li&gt;    &lt;li&gt;Added support for running standalone FxCop in addition to running VS 2008 Managed Code Analysis. &lt;/li&gt;    &lt;li&gt;Added targets to test the install and uninstall of the Windows installer created. &lt;/li&gt;    &lt;li&gt;Consolidated the CodeDocumentationBuild to become part of the DeploymentBuild. &lt;/li&gt;    &lt;li&gt;Removed the QTP integration as this was not a requirement for the new project. If you want to integrate QTP, please refer to the QtpBuild of the &lt;a href="http://sites.google.com/site/fromthedevtrenches/downloads/ContinuousIntegration-FromTheorytoPractice.pdf?attredirects=0&amp;amp;d=1"&gt;first edition&lt;/a&gt; of the guide. &lt;/li&gt;    &lt;li&gt;Used the latest version of all the tools available.&amp;#160; The tools used in the guide are VS 2008, Subversion, CruiseControl.NET, MSBuild, MSBuild.Community.Tasks, NUnit/MbUnit, FxCop, TypeMock/Rhino.Mocks, WiX, Sandcastle, NCover, NCoverExplorer and NDepend. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;I hope you find it to be a useful resource for assisting you with creating your own CI process by harnessing the power of MSBuild!&amp;#160; If you have any questions, additional remarks or any suggestions, feel free to drop me a comment.&lt;/p&gt;  &lt;h2&gt;Download&lt;/h2&gt; Here are the links:  &lt;ol&gt;   &lt;li&gt;&lt;a href="http://sites.google.com/site/fromthedevtrenches/downloads/ContinuousIntegration-FromTheorytoPractice%2C2ndEd.pdf?attredirects=0&amp;amp;d=1"&gt;PDF Guide&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;&lt;a href="http://sites.google.com/site/fromthedevtrenches/downloads/ContinuousIntegration-FromTheorytoPractice%2C2ndEd.zip?attredirects=0&amp;amp;d=1"&gt;Code and Build artifacts&lt;/a&gt;&lt;/li&gt; &lt;/ol&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-6920860119032252962?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/Un8FywGEkf0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/6920860119032252962/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2009/11/continuous-integration-from-theory-to.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6920860119032252962?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/6920860119032252962?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/Un8FywGEkf0/continuous-integration-from-theory-to.html" title="Continuous Integration in .NET: From Theory to Practice 2nd Edition" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh6.ggpht.com/_ziqU4IJY4Uc/TIOQLngstyI/AAAAAAAAAtY/jHcvXsJWv68/s72-c/TeamPuzzle%5B4%5D.jpg?imgmax=800" height="72" width="72" /><thr:total>2</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2009/11/continuous-integration-from-theory-to.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEUCRns-eSp7ImA9Wx5QEUw.&quot;"><id>tag:blogger.com,1999:blog-4775121157402872976.post-2950548967276587544</id><published>2009-10-31T22:50:00.001+02:00</published><updated>2010-08-29T22:04:27.551+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-08-29T22:04:27.551+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Tools" /><title>My Ultimate .NET Development Tools 2010 Edition</title><content type="html">&lt;p&gt;Here is my 2010 updated list of development tools that I prefer to use when doing .NET development.&amp;#160; I specifically decided to not include any third party control/report libraries.&amp;#160; I focus instead on the tools that assist me in crafting high-quality code quickly and effectively.&lt;/p&gt;  &lt;h2&gt;Categories&lt;/h2&gt;  &lt;ul&gt;   &lt;li&gt;IDE = Develop/generate/refactor code within the VS IDE or separate IDE &lt;/li&gt;    &lt;li&gt;SCM = Software Configuration Management (Source Control etc.) &lt;/li&gt;    &lt;li&gt;TDD = Test Driven Development &lt;/li&gt;    &lt;li&gt;DBMS = Database Management Systems &lt;/li&gt;    &lt;li&gt;CI = Continuous Integration &lt;/li&gt;    &lt;li&gt;FR = Frameworks (Persistence, AOP, Inversion of Control, Logging etc.) &lt;/li&gt;    &lt;li&gt;UT = Utility Tools &lt;/li&gt;    &lt;li&gt;CA = Code Analysis (Static + Dynamic) &lt;/li&gt;    &lt;li&gt;TC = Team Collaboration (Bug tracking, Project management etc.) &lt;/li&gt;    &lt;li&gt;MD = Modelling &lt;/li&gt;    &lt;li&gt;QA = Testing Tools &lt;/li&gt;    &lt;li&gt;DP = Deployment (Installations etc.) &lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;&amp;#160;&lt;/h2&gt;  &lt;h2&gt;Tools&lt;/h2&gt; * = free/open source  &lt;br /&gt;  &lt;ol&gt;   &lt;li&gt;[IDE] &lt;a href="http://msdn2.microsoft.com/en-us/vstudio/default.aspx" target="_blank"&gt;Visual Studio 2010 Premium Edition&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;[IDE] &lt;a href="http://www.jetbrains.com/resharper" target="_blank"&gt;ReSharper&lt;/a&gt; for refactoring, unit test runner and so much more&lt;/li&gt;    &lt;li&gt;[IDE] &lt;a href="http://www.codesmithtools.com/" target="_blank"&gt;CodeSmith&lt;/a&gt; for generating code.&amp;#160; Also consider T4 with &lt;a href="http://www.visualt4.com/" target="_blank"&gt;Clarius’s Visual T4&lt;/a&gt; Editor.&amp;#160;&amp;#160; &lt;/li&gt;    &lt;li&gt;[IDE]* &lt;a href="http://submain.com/products/ghostdoc.aspx" target="_blank"&gt;GhostDoc&lt;/a&gt; for inserting xml code comments &lt;/li&gt;    &lt;li&gt;[IDE] &lt;a href="http://www.altova.com/" target="_blank"&gt;Altova Xml Suite&lt;/a&gt; for any xml related work.&amp;#160; &lt;a href="http://www.wmhelp.com/" target="_blank"&gt;XmlPad&lt;/a&gt; is the best, free alternative I know of. &lt;/li&gt;    &lt;li&gt;[DBMS] &lt;a href="http://www.microsoft.com/sql/" target="_blank"&gt;SqlServer 2008&lt;/a&gt; for DBMS &lt;/li&gt;    &lt;li&gt;[SCM]* &lt;a href="http://subversion.tigris.org/" target="_blank"&gt;Subversion&lt;/a&gt; for source control &lt;/li&gt;    &lt;li&gt;[SCM]* &lt;a href="http://tortoisesvn.tigris.org/" target="_blank"&gt;TortoiseSVN&lt;/a&gt; as windows shell extension for Subversion &lt;/li&gt;    &lt;li&gt;[SCM] &lt;a href="http://tortoisesvn.tigris.org/" target="_blank"&gt;VisualSVN&lt;/a&gt; for integration of TortoiseSVN into VS.&amp;#160; &lt;a href="http://ankhsvn.open.collab.net/" target="_blank"&gt;AnkhSVN&lt;/a&gt; is the best, free alternative I know of. &lt;/li&gt;    &lt;li&gt;[SCM]* &lt;a href="http://kdiff3.sourceforge.net/" target="_blank"&gt;KDiff3&lt;/a&gt; for merging &lt;/li&gt;    &lt;li&gt;[TDD]* &lt;a href="http://www.nunit.com/" target="_blank"&gt;NUnit&lt;/a&gt; as preferred xUnit testing framework &lt;/li&gt;    &lt;li&gt;[TDD]* &lt;a href="http://code.google.com/p/moq/" target="_blank"&gt;moq&lt;/a&gt; as mock framework. &lt;/li&gt;    &lt;li&gt;[TDD] &lt;a href="http://www.ncover.com/" target="_blank"&gt;NCover&lt;/a&gt; for code coverage stats &lt;/li&gt;    &lt;li&gt;[CI]* &lt;a href="http://www.jetbrains.com/teamcity" target="_blank"&gt;TeamCity&lt;/a&gt; as build server &lt;/li&gt;    &lt;li&gt;[CI]* &lt;a href="http://msbuildextensionpack.codeplex.com/" target="_blank"&gt;MSBuild Extension Pack&lt;/a&gt; for additional MSBuild tasks. &lt;/li&gt;    &lt;li&gt;[FR]* &lt;a href="http://logging.apache.org/log4net/"&gt;log4net&lt;/a&gt; as logging framework.&amp;#160; Also see &lt;a href="http://www.log4view.com/" target="_blank"&gt;Log4View&lt;/a&gt; for an excellent UI for the log files. &lt;/li&gt;    &lt;li&gt;[FR]* &lt;a href="http://www.antlr.org/" target="_blank"&gt;ANTLR&lt;/a&gt; and &lt;a href="http://www.antlr.org/works/index.html" target="_blank"&gt;ANTLRWorks&lt;/a&gt; for creating custom DSL’s.&lt;/li&gt;    &lt;li&gt;[FR] &lt;a href="http://www.sharpcrafters.com/" target="_blank"&gt;PostSharp&lt;/a&gt; as Aspect Oriented Programming framework &lt;/li&gt;    &lt;li&gt;[FR]* &lt;a href="http://ninject.org/" target="_blank"&gt;Ninject&lt;/a&gt; as IoC container &lt;/li&gt;    &lt;li&gt;[FR]* &lt;a href="http://code.google.com/p/runsharp/" target="_blank"&gt;RunSharp&lt;/a&gt; for generating IL at run-time&lt;/li&gt;    &lt;li&gt;[FR] &lt;a href="http://www.mindscape.co.nz/products/LightSpeed/default.aspx" target="_blank"&gt;MindScape LightSpeed&lt;/a&gt; as my Object-Relational-Mapper.&amp;#160; &lt;a href="http://www.nhibernate.org/" target="_blank"&gt;NHibernate&lt;/a&gt; is the best free alternative I’m aware of.&amp;#160; &lt;/li&gt;    &lt;li&gt;[UT]* &lt;a href="http://www.red-gate.com/products/reflector/index.htm" target="_blank"&gt;Reflector&lt;/a&gt; to drill down to the guts of any code library (also check-out the &lt;a href="http://www.codeplex.com/reflectoraddins" target="_blank"&gt;nice plug-ins&lt;/a&gt;) &lt;/li&gt;    &lt;li&gt;[UT] &lt;a href="http://firstfloorsoftware.com/silverlightspy/" target="_blank"&gt;Silverlight Spy&lt;/a&gt; to dissect any Silverlight application. &lt;/li&gt;    &lt;li&gt;[UT] &lt;a href="http://www.regexbuddy.com/" target="_blank"&gt;RegexBuddy&lt;/a&gt; for managing those difficult regular expressions.&amp;#160; &lt;a href="http://tools.osherove.com/CoolTools/Regulator/tabid/185/Default.aspx" target="_blank"&gt;Regulator&lt;/a&gt; is the best, free alternative I know of.&amp;#160; &lt;/li&gt;    &lt;li&gt;[UT]* &lt;a href="http://www.linqpad.net/" target="_blank"&gt;LINQPad&lt;/a&gt; as a easy way to query SQL databases using LINQ and as a general scratchpad application to test C#/VB.NET code snippets.&lt;/li&gt;    &lt;li&gt;[UT]* &lt;a href="http://www.fiddlertool.com/" target="_blank"&gt;Fiddler&lt;/a&gt; to debug all your HTTP traffic in IE.&amp;#160;&amp;#160; Also see the &lt;a href="http://blogs.msdn.com/nexpert/" target="_blank"&gt;neXpert plugin&lt;/a&gt; for monitoring performance problems. &lt;/li&gt;    &lt;li&gt;[UT]* &lt;a href="http://www.getfirebug.com/" target="_blank"&gt;Firebug&lt;/a&gt; to assist with testing web applications running in Firefox. Also see &lt;a href="http://developer.yahoo.com/yslow/" target="_blank"&gt;YSlow&lt;/a&gt; add-on for performance testing and &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/60" target="_blank"&gt;Web Developer&lt;/a&gt; add-on for additional Firefox web development tools. &lt;/li&gt;    &lt;li&gt;[CA]* &lt;a href="http://msdn.microsoft.com/en-us/library/bb429476(VS.80).aspx" target="_blank"&gt;FxCop&lt;/a&gt; to enforce .NET coding guidelines &lt;/li&gt;    &lt;li&gt;[CA] &lt;a href="http://www.ndepend.com/" target="_blank"&gt;NDepend&lt;/a&gt; to get all the static code metrics I'd ever want &lt;/li&gt;    &lt;li&gt;[CA] &lt;a href="http://www.red-gate.com/products/ants_profiler/index.htm" target="_blank"&gt;ANTS Profiler&lt;/a&gt; for performance and memory profiling &lt;/li&gt;    &lt;li&gt;[MD] &lt;a href="http://www.sparxsystems.com/" target="_blank"&gt;Enterprise Architect&lt;/a&gt; to do UML Modelling and Model Driven Design if required. Alternatively use Visio with these &lt;a href="http://www.softwarestencils.com/uml/index.html"&gt;simple templates&lt;/a&gt;.&amp;#160; &lt;/li&gt;    &lt;li&gt;[MD]* &lt;a href="http://freemind.sourceforge.net/"&gt;FreeMind&lt;/a&gt; as mind mapping tool &lt;/li&gt;    &lt;li&gt;[TC]* &lt;a href="http://www.screwturn.eu/" target="_blank"&gt;ScrewTurn Wiki&lt;/a&gt; for team collaboration &lt;/li&gt;    &lt;li&gt;[QA]* &lt;a href="http://www.soapui.org/" target="_blank"&gt;Eviware soapUI&lt;/a&gt; for functional and load testing of SOA web services &lt;/li&gt;    &lt;li&gt;[QA]* &lt;a href="http://www.telerik.com/products/web-testing-tools/webaii-framework-features.aspx" target="_blank"&gt;Telerik WebAii Testing Framework&lt;/a&gt; for automated regression testing of Web 2.0 apps &lt;/li&gt;    &lt;li&gt;[DP]* &lt;a href="http://wix.sourceforge.net/"&gt;Windows Installer XML (WiX)&lt;/a&gt; for creating Windows Installers&lt;/li&gt; &lt;/ol&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4775121157402872976-2950548967276587544?l=fromthedevtrenches.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/FromTheSoftwareDevelopmentTrenches/~4/uN9lsyZVQcg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://fromthedevtrenches.blogspot.com/feeds/2950548967276587544/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://fromthedevtrenches.blogspot.com/2009/10/ultimate-net-development-tools.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/2950548967276587544?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/4775121157402872976/posts/default/2950548967276587544?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/FromTheSoftwareDevelopmentTrenches/~3/uN9lsyZVQcg/ultimate-net-development-tools.html" title="My Ultimate .NET Development Tools 2010 Edition" /><author><name>Carel Lotz</name><uri>http://www.blogger.com/profile/13701537592037249529</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="32" src="http://4.bp.blogspot.com/_ziqU4IJY4Uc/Suw8cQOU-oI/AAAAAAAAAr0/HgqjPgRSegE/S220/Carel+Lotz.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://fromthedevtrenches.blogspot.com/2009/10/ultimate-net-development-tools.html</feedburner:origLink></entry></feed>

