tag:blogger.com,1999:blog-47751211574028729762024-03-18T11:47:48.470+02:00From The Software Development TrenchesThoughts on software developmentCarel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.comBlogger35125tag:blogger.com,1999:blog-4775121157402872976.post-51103410419686821622017-03-21T16:50:00.000+02:002017-03-21T16:50:54.872+02:00Moving blog to Github PagesThe blog has been pretty much inactive. I would like to start blogging a bit more again, but want to use a more powerful blogging platform that allows me to use Markdown. After some investigation, I've decided on using GitHub pages with Jekyll. For the few still subscribed to my feed, you can subscribed to the new blog located at <a href="https://cjlotz.github.io/">https://cjlotz.github.io/</a>. I'm leaving the existing blog content as is.Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com5tag:blogger.com,1999:blog-4775121157402872976.post-23354227777980239472015-12-09T00:11:00.000+02:002015-12-09T00:15:15.643+02:00Messaging Plugin for Xamarin 3.0I've just published an update to the <a href="https://www.nuget.org/packages/Xam.Plugins.Messaging/">Messaging Plugin for Xamarin</a> that includes support for the Windows Universal Platform (thanks to @JamesMontemagno). The update introduces a breaking change whereby the default namespace for the plugin changes to <b>Plugin.Messaging</b> to align with the naming strategy for Xamarin plugins proposed by James Montemagno <a href="http://motzcod.es/post/134355371052/build-apps-faster-with-plugins-for-xamarin">in his latest round of Xamarin plugin updates</a>. Due to this breaking change, the version of the plugin has been bumped to v3.0.0.Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com6tag:blogger.com,1999:blog-4775121157402872976.post-10716540927044415992014-12-25T20:01:00.001+02:002014-12-25T20:01:24.615+02:00Messaging Plugin for Xamarin and Windows 2.0.0<p>I’ve been having some fun taking part in the <a href="http://blog.xamarin.com/holiday-contest-create-a-plugin-for-xamarin/" target="_blank">Xamarin Holiday contest for creating a Xamarin plugin</a>. My entry for the competition is a <a href="https://github.com/cjlotz/Xamarin.Plugins" target="_blank">Messaging Plugin</a>. The Messaging plugin makes it possible to make a phone call, send a SMS or send an e-mail using the default messaging applications on the different mobile platforms. </p> <p>I’ve been slowly adding new features and have just published a new version of the plugin that adds support for sending attachments as part of an e-mail. In addition to adding attachments support I did some clean-up and refactoring on the plugin API. Unfortunately this introduces a few breaking changes and I’ve therefore decided to make the new version a major update (2.0.0).</p> <p>Here is a list of supported features for v2:</p> <ul> <li>Send SMS (supported on iOS, Android, WinPhone 8, WinPhone RT) <li>Make Phone Call (supported on iOS, Android, WinPhone 8, WinPhone RT) <li>Send Email (supported on iOS, Android, WinPhone 8, WinPhone RT and limited support on WinStore via <font color="#666666" face="Consolas">mailto</font> protocol) <li>Send HTML Email (supported on iOS, Android) <li>Send Email Attachments (supported on iOS, Android, WinPhone RT)</li></ul> <p>Here is the release notes for v2:</p> <ul> <li>Added support for attachments via <font color="#666666" face="Consolas">IEmailAttachment</font> abstraction <li>Added <font color="#666666" face="Consolas">IEmailMessage</font> abstraction <li><strong>Breaking change</strong>: Deprecated <font color="#666666" face="Consolas">EmailMessageRequest</font>. Construct <font color="#666666" face="Consolas">IEmailMessage</font> using <font color="#666666" face="Consolas">EmailMessageBuilder</font> instead. <li><strong>Breaking change</strong>: Changed <font color="#666666" face="Consolas">IEmailTask.SendMail</font> overload to use <font color="#666666" face="Consolas">IEmailMessage</font>. <li><strong>Breaking change</strong>: Deprecated <font color="#666666" face="Consolas">Lotz.Xamarin.Messaging.Abstractions</font> namespace. Use <font color="#666666" face="Consolas">Lotz.Xamarin.Messaging</font> instead.</li></ul> <p>So head over to <a href="https://www.nuget.org/packages/Xam.Plugins.Messaging/" target="_blank">NuGet</a> to install the latest version. Full documentation on how to use the API and examples for using the plugin for the different platforms can be found in the <a href="https://github.com/cjlotz/Xamarin.Plugins" target="_blank">GitHub</a> repository. </p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com46tag:blogger.com,1999:blog-4775121157402872976.post-71567379319554163702014-12-15T11:14:00.001+02:002014-12-15T11:14:56.276+02:00TFS Release Notes Generator on GithubA while back I wrote an article on how to <a href="http://fromthedevtrenches.blogspot.com/2013/04/automatically-generate-tfs-release.html">generate release notes from a TFS Work Item Query</a> into a PDF output file. I recevied some requests for access to the full source code and not only the snippets showed in the blogpost. I've now uploaded the solution on <a href="https://github.com/cjlotz/ReleaseNotes">Github</a>. Have fun :-)Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com2tag:blogger.com,1999:blog-4775121157402872976.post-72002836284592426272013-07-22T07:52:00.001+02:002013-07-22T07:52:10.517+02:00Silverlight 5 PivotViewer Localization<p>We’ve recently started using the Silverlight 5 <a href="http://www.microsoft.com/silverlight/pivotviewer/">PivotViewer control</a> in On Key Express as a great way for visualizing the Work Orders showing the work list that needs to be completed/has been completed. Here is some screenshots showing the different “cards” of information for the Work Orders at different zoom levels.</p> <p><a href="http://lh4.ggpht.com/-XuUS4klCvLU/UezIZw5s4lI/AAAAAAAAAyA/k8E1mYfTkME/s1600-h/image%25255B3%25255D.png"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="http://lh5.ggpht.com/-kI1MYKT80TM/UezIbnnGEnI/AAAAAAAAAyI/ERdPu0adQOg/image_thumb%25255B1%25255D.png?imgmax=800" width="537" height="428"></a></p> <p>Small Card View</p> <p><a href="http://lh3.ggpht.com/-hbflRWRufeE/UezId5OX4tI/AAAAAAAAAyQ/OXfWER_ad6U/s1600-h/image%25255B8%25255D.png"><img title="image" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="image" src="http://lh3.ggpht.com/-HnWNU4MuEUA/UezIeyIDooI/AAAAAAAAAyY/Mk_72ZeDXDw/image_thumb%25255B4%25255D.png?imgmax=800" width="538" height="434"></a></p> <p>Large Card View</p> <p>One of the great features of On Key Express is the ability for clients to translate the system into any language. This is great feature for customers who have engineers working across the globe as they can customise the system into any language they which to support. We supply the default English translation but the clients can even decide to change the English translation if they have certain client specific terminology they want to use.</p> <p>This language feature however imposes an important restriction of any third party control that we use – we need the ability to translate any resource displayed by the control. We make extensive use of the excellent <a href="http://www.telerik.com/products/silverlight/overview.aspx">Telerik RadControls for Silverlight</a>. Fortunately these controls are <a href="http://www.telerik.com/help/silverlight/common-localization.html">fully localizable</a> by hooking up a custom ResourceManager to override the default resources being used by the Grids and other controls. </p> <p>The PivotViewer control has quite a few resources. It ships with support for a few languages out-of-the-box through providing the resources in separate System.Windows.Controls.Pivot.resources.dll resource assemblies. By setting the <a href="http://msdn.microsoft.com/en-us/library/system.windows.controls.pivot.pivotviewer.itemculture(v=vs.95).aspx">ItemCulture</a> property you are able to use the different out-of-the-box translations shipped with the control. However, unlike the Telerik controls there is however no easy way to hook into the control to override the resources being used. We can create additional resources assemblies for different languages but as mentioned previously, the client decides what additional languages they want to support. </p> <p>We therefore needed a way to hook into the PivotViewer to inject our own Resource Provider that will use the client provided resource translations. Technically we store the clients translations in a database that is periodically synchronised with the client devices. After looking at the PivotViewer using Reflector, we confirmed that it makes use of the usual an internal static Resources class that is generated whenever you add .resx files to a project. The Resources wrapper internally makes use of a ResourceManager that uses the current culture to access the language specific resource file. We needed the ability to intercept the calls being made by this ResourceManager. We also wanted the ability to still use the existing Microsoft resource assembly as the default fallback mechanism for any of the resources that we don’t want the clients to translate. There includes the numerous exceptions and other design time resources which the clients aren’t interested in. </p> <p>With this in mind, we created the following <strong>PivotViewerResourceManager</strong> wrapper class:</p><script src="https://gist.github.com/cjlotz/6051474.js"></script> <p>Notice that the class is a simple ResourceManager wrapper around the existing Microsoft resource assembly. When override the GetString method to allow us to first do an external lookup for the resource using our IResourceProvider interface. If we do not have an external translation, we simply delegate to the Microsoft provided resource. We adopted the convention of prefixing all the client provided translations for the PivotViewer with the “MSPivot” prefix as it makes it easier to identify all the translations related directly to the control. With all of this in place we simply added a trigger to the PivotViewer XAML to load and inject our PivotViewerResourceManager when the control is loaded via the InjectResourceManager method.</p> <p>Here is a sample screen shot of our ResourceManager in action with the PivotViewer. Notice that some of the resources for which we provide translations are show in a different language whilst the rest of the control falls back to using the default MS provider resources. </p> <p><a href="http://lh5.ggpht.com/-c9kZb4pXfUw/UezIg6_V7FI/AAAAAAAAAyg/M5CSjgSCP-0/s1600-h/image%25255B13%25255D.png"><img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image" src="http://lh6.ggpht.com/-sPv5QQn69_U/UezIiNxF3NI/AAAAAAAAAyo/evLhX8PaQKY/image_thumb%25255B7%25255D.png?imgmax=800" width="540" height="415"></a></p> <p>Sweet!</p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com4tag:blogger.com,1999:blog-4775121157402872976.post-32647009360529272962013-04-02T21:43:00.002+02:002013-04-02T21:46:53.377+02:00Automatically Generate TFS Release Notes to PDF<h3>Background</h3>At Pragma we've been improving on some of our deployment practices during the past few releases. I've always been a great proponent of trying to automate as much of the deployment process as possible. One of the aspects that we improved on recently was the ability to automatically generate the Release Notes from our Team Foundation Server repository with every daily build of our software. This automation gives us quite a few benefits:<br />
<ol><li>Visibility into what's included with every build from the beginning of a release</li>
<li>Ability to QA the Release Notes earlier in the development cycle as part of our daily builds</li>
<li>Use of our existing TFS work items as the source for feedback, i.e. no context is lost between developers telling the technical writer what to include in the Release Notes. The technical writer only needs to check the grammar and spelling of the TFS Work Item feedback.</li>
<li>No manual intervention required to get the bulk of the Release Notes document generated</li>
</ol><div>After doing some research on the web and looking at solutions like <a href="http://tfschangelog.codeplex.com/" target="_blank">TFSChangeLog</a> and this <span id="goog_943058448"></span><a href="http://www.codeproject.com/Articles/305598/TFS-API-ndash-Release-Notes-From-TFS-Builds" target="_blank">CodeProject<span id="goog_943058449"></span> article</a>, we decided to roll our own due to some unique requirements within our environment. The solution turned out to work quite elegantly and I hope this blog post will provide some pointers for other folks on how to go about implementing something similar for their own environments.</div><div><br />
</div><h3>Requirements</h3><div>Here is a run-down of some of our requirements:</div><div><ol><li>We want to be able to merge some manually authored content into the Release Notes document. Sections like <b>What's New</b>, <b>Modifications</b> and <b>Maintenance</b> typically contain functionality that are implemented by various TFS Work Items (Product Backlog Items, Tasks etc). So we wanted the ability to manually author these sections and merge the content with remainder of the document that is automatically generated.</li>
<li>We want the ability to selectively filter out some Work Items from being included in the Release Notes document by running a custom TFS Query. An example of Work Items that we want to exclude are the internal bugs that were discovered for new functionality not yet released into production. </li>
<li>We want to use MS Word to author the manual content to make use of our existing corporate stylesheets</li>
<li>We want the output to be available as a PDF</li>
<li>We want command line support to allow us to automate the process as part of our daily builds using TeamCity</li>
<li>We want the PDF to use bookmarks to enable easy navigation between the different sections</li>
<li>We want the PDF to use our corporate branding/style</li>
</ol></div><div>With the list of requirements, we set out to build a solution to satisfy all of these. <br />
<br />
</div><h3>Solution</h3><div>Setting up a Word template to satisfy requirement #1 and #3 was a snap to do. As we want the final output to be available as PDF, we save the Word document as a PDF once it has been updated. To satisfy requirement #2 we created a TFS Query with the relevant query conditions to filter out unwanted Work Items. </div><div><br />
</div><div>With the manually created PDF and the TFS Query returning the list of work items to use, we started looking at some code for generating a PDF from the Work Item contents. We started off by creating a <b>CommandLineOptions</b> class to encapsulate all the different command line parameters to satisfy requirement #5:<br />
<br />
<script src="https://gist.github.com/cjlotz/5290054.js"></script><br />
<div>The <b>AppAction</b><i> </i>enumeration is used to indicate whether to run the app as a command line utility or to run the application using a GUI which allows you to manually specify the parameters to use for driving the report generation process - this is especially useful for testing purposes. Just for reference, here is a quick view of the user interface:</div><br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://1.bp.blogspot.com/-zx4zQuRU95c/UVpoDklP4AI/AAAAAAAAAwM/CVQoHJTcNII/s1600/ReleaseNotesGenerator.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="464" src="http://1.bp.blogspot.com/-zx4zQuRU95c/UVpoDklP4AI/AAAAAAAAAwM/CVQoHJTcNII/s640/ReleaseNotesGenerator.png" width="640" /></a></div><br />
The next step was to create a <b>ReportRunner</b> class to take these settings and generate the report in the PDF format:<br />
<br />
</div><div><script src="https://gist.github.com/cjlotz/5286255.js"></script><br />
</div><div>Using the TFS API to programmatically query the contents of the work items was quite easy to do as illustrated through the <b>ConnectToTfs</b> and <b>GenerateReleaseNoteWorkItem</b> methods above. With the Work Item information now processed and available in memory, the final step in the generation process was to take the list of processed work items, write them to a PDF file and finally merge the contents of this generated file with the output of the manually created PDF file. This turned out to be quite an interesting exercise and by far the most challenging aspect of the whole solution :-)<br />
<br />
</div><div><h3>Generating the PDF</h3></div><div>After looking at various options for generating a PDF programmatically, we decided to use the C# open source port of the well-known Java <a href="http://itextpdf.com/" target="_blank">iText</a> library called <a href="http://sourceforge.net/projects/itextsharp/" target="_blank">iTextSharp</a>. Through reading <a href="http://kuujinbo.info/code_index.aspx?tab=2" target="_blank">various</a> <a href="http://www.mikesdotnetting.com/Article/80/Create-PDFs-in-ASP.NET-getting-started-with-iTextSharp" target="_blank">articles</a> on the web (there is also this great <a href="http://www.manning.com/lowagie2/" target="_blank">Manning Book</a> on the Java version), we eventually figured out how to generate, merge and create a PDF to satisfy the remainder of the requirements. <br />
<br />
On a high level, the process for generating the PDF turned out as follows:<br />
<ol><li>Create new blank PDF</li>
<li>Add a front page</li>
<li>Add (merge) the contents of the manual PDF into the new blank PDF whilst keeping track of the bookmarks contained within the manual document (see Requirement #6)</li>
<li>Run through the list of processed work items to add the document content for them into relevant sections in the new PDF</li>
<li>Re-bookmark the whole document to enable easy navigation throughout the whole PDF in support of requirement #6.</li>
</ol></div><div>This high-level process was implemented in the <b>Publish</b> method of the <b>ReleaseNotesPdfWriter</b> class.<br />
<br />
<script src="https://gist.github.com/cjlotz/5294738.js"></script><br />
To add the front page and also include a custom footer on every page containing the build version, generation time stamp as well as page number, we created a <a href="https://gist.github.com/cjlotz/5294881" target="_blank">ReleaseNotesPdfPageEvents</a> class to implement the <b>IPdfPageEvent</b> interface that iTextSharp provides for executing custom logic when a PDF document is opened/closed, new paragraphs, sections are added etc. This class is then assigned to <b>PageEvent</b> of the PDF writer to ensure that the custom logic executes as part of the PDF generation process (see line 16).<br />
<br />
After adding the front page, the content of the manual PDF is merged into the new document (lines 30-35). Keeping track of the bookmarks turned out to be quite an interesting exercise and is done as part of the <a href="https://gist.github.com/cjlotz/5295015" target="_blank">Merge</a> method.<br />
<br />
After merging the existing content, we process the in-memory list of work item information by firstly grouping the Work Items based on their resolution types into sections like "How do I", "Bug Fixes" etc. (lines 38-41) and thereafter writing these sections into the document using the <b>WriteWorkItems</b> method:<br />
<br />
<script src="https://gist.github.com/cjlotz/5295215.js"></script><br />
For every new section we add an additional bookmark into the Bookmarks collection to make sure that we have a complete list of bookmarks for all the available sections in the document (see line 14). The final step in the generation process is to add these bookmarks into the new document using the <b>CreateBookmarks</b> method.<br />
<br />
<script src="https://gist.github.com/cjlotz/5295274.js"></script><br />
<h3>Conclusion</h3><div>Here is a screenshot of an example report generated for our latest release to give you an idea of what is possible using the solution described above. I think you'll agree that the content looks quite professional.</div><div><br />
</div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="http://2.bp.blogspot.com/-nb0__FaF3GU/UVsxNPCK4_I/AAAAAAAAAws/GPPTe4XUoLs/s1600/ReleaseNotesGeneratorOutput.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="380" src="http://2.bp.blogspot.com/-nb0__FaF3GU/UVsxNPCK4_I/AAAAAAAAAws/GPPTe4XUoLs/s640/ReleaseNotesGeneratorOutput.png" width="640" /></a></div><div><br />
</div><div>I trust you find the above mentioned pointers useful in creating your own solution.</div><br />
</div>Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com11tag:blogger.com,1999:blog-4775121157402872976.post-76900351607673249202012-12-28T07:16:00.001+02:002012-12-28T07:16:43.258+02:00Async support for running Silverlight Unit Tests<p>One of the great new features included with .NET 4.5 and Visual Studio 2012 is the <a href="http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx" target="_blank">async/await support</a> for writing more elegant multi-threaded code in C# or Visual Basic. Support for writing tests that make use of the async/await keywords is available for the Microsoft Test Framework as well as most of the other popular xUnit testing frameworks like NUnit. In addition to providing support for async/await baked into the compilers for Visual Studio 2012 and .NET 4.5, Microsoft has also released the <a href="http://nuget.org/packages/Microsoft.CompilerServices.AsyncTargetingPack" target="_blank">Async Targeting pack for Visual Studio 2012</a> that enables projects targeting .NET 4.0 or Silverlight 5 to use the Async language feature in C# and Visual Basic code.</p> <p>Using it in your Silverlight 5 code is quite handy – especially when <a href="http://10rem.net/blog/2012/05/22/using-async-and-await-in-silverlight-5-and-net-4-in-visual-studio-11-with-the-async-targeting-pack" target="_blank">invoking web services</a> from the client. However, the Microsoft Test Framework for Silverlight has not been extended to support running these asynchronous tests. However, in a recent <a href="http://www.sharpgis.net/post/2012/12/21/Hacking-the-Silverlight-Unit-Tests-to-support-returning-Task.aspx" target="_blank">blog post</a> by Morten Nielsen he shows how it is possible to go about adding this support to the Silverlight Test Framework. He provides a customized version of the Silverlight Test Framework, but also urges us to <a href="http://silverlight.codeplex.com/workitem/11457?PendingVoteId=11457" target="_blank">go vote</a> for getting this added directly to the official <a href="http://silverlight.codeplex.com/" target="_blank">Silverlight Toolkit</a>. </p> <p>I know a lot of development shops like ourselves still have quite a substantial amount of Silverlight code to maintain, so please <a href="http://silverlight.codeplex.com/workitem/11457?PendingVoteId=11457" target="_blank">go and vote for the issue</a> to get Microsoft to add support for it in the Silverlight Toolkit.</p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com2tag:blogger.com,1999:blog-4775121157402872976.post-19967409605119011212012-11-19T13:19:00.001+02:002012-11-19T13:19:47.945+02:00FxCop Standalone for VS 2012, .NET 4.5 and Portable Libraries<p>In our current team environment we are using the VS 2012 Professional SKU with a MSDN subscription due to the cost savings it affords us. That implies that we miss out on features like the integrated Code Analysis. Up till VS 2010, Microsoft released an updated edition of the Code Analysis engine with the standalone FxCop installation. That implied that even though we didn’t get the tooling integrated into Visual Studio directly, at least we could use the standalone edition of FxCop to execute the same set of Code Analysis rules on our code base - albeit in a bit more laborious fashion.</p> <p>With VS 2012 Microsoft has not yet released an update to the standalone FxCop. Here’s the <a href="http://social.msdn.microsoft.com/Forums/en-US/vstscode/thread/6c85e39b-0952-4166-9764-5b37d71adda0/#6c85e39b-0952-4166-9764-5b37d71adda0" target="_blank">MSDN forum post</a> where I raised the issue as to when an update will be released. The current standalone edition also doesn’t seem to support the new Portable Library format being used to cross target different .NET platforms. Following the advise on the forum post I’ve created an <a href="http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3243367-update-standalone-fxcop-to-support-net-4-5-and-po" target="_blank">UserVoice issue</a> to request an update. So if you are in the same boat as to using the standalone edition, please head over to UserVoice and go vote for <a href="http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/3243367-update-standalone-fxcop-to-support-net-4-5-and-po" target="_blank">the issue</a> to get it resolved. Thanks.</p> <p>PS: Btw, if you would like to run the standalone FxCop in VS, you might want to consider the <a href="http://fxcopintegrator.codeplex.com/" target="_blank">FxCop Integrator</a>. Haven’t used it, but it seems promising although there hasn’t been an update for a while.</p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com1tag:blogger.com,1999:blog-4775121157402872976.post-6508568835831252712012-04-16T10:52:00.001+02:002012-04-16T10:52:12.077+02:00Practical Performance Profiling E-book<p>The folks at <a href="http://www.red-gate.com/" target="_blank">RedGate</a>, makers of some quality .NET and SQL Server tools like <a href="http://www.reflector.net/" target="_blank">Reflector</a>, ANTS <a href="http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/index2" target="_blank">Memory</a> and <a href="http://www.red-gate.com/products/dotnet-development/ants-performance-profiler/" target="_blank">Performance</a> Profiler, <a href="http://www.red-gate.com/products/dba/sql-monitor/" target="_blank">SQL Monitor</a> (and much more) have published an <a href="http://www.red-gate.com/products/dotnet-development/ants-performance-profiler/entrypage/practical-performance-profiling?utm_source=simpletalk&utm_medium=email-main&utm_content=appebook&utm_campaign=antsperformanceprofiler" target="_blank">excellent, free book on performance profiling</a>. <strong><em>Practical Performance Profiling</em></strong> by <strong><em>Jean-Philippe Gouigoux </em></strong>seems like a wonderful comprehensive guide for improving application performance by understanding performance bottlenecks from every possible angle. Do yourself a favour and register to get your own copy soon. Happy profiling <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://lh3.ggpht.com/-nwcnE0CUmZs/T4vduRIuoAI/AAAAAAAAAvw/ZBLcQJPKki4/wlEmoticon-smile%25255B2%25255D.png?imgmax=800"></p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com6tag:blogger.com,1999:blog-4775121157402872976.post-73214040075548747902012-02-08T11:54:00.001+02:002012-02-08T11:54:56.441+02:00Silverlight 5 Upgrade Woes<blockquote></blockquote> <p>We recently struggled to upgrade the UI of On Key, <a href="http://www.pragmaworld.net/" target="_blank">Pragma’s</a> Enterprise Asset Management System (EAMS) to Silverlight 5. We struggled with getting Silverlight 5 binaries for a lot of the open source projects (<a href="http://code.google.com/p/moq/issues/detail?id=330" target="_blank">Moq</a>, Castle.Core), but it was the lack of development tooling support in Visual Studio 2010 that really disappointed us. I can understand that the open source projects are slack in providing support for Silverlight 5. We solved the problem by getting the source code and creating Silverlight 5 binaries ourselves. However our hands are cut off when it comes the development tooling in Visual Studio. Expression Blend 5 is still only in preview edition with <a href="http://forums.silverlight.net/t/244259.aspx/1" target="_blank">no word</a> <a href="http://social.expression.microsoft.com/Forums/en/blend/thread/1d758c96-23f9-469c-aea4-3445fad308af" target="_blank">on when</a> a final version that supports the SL 5 RTW will be provided. Code Analysis (FxCop) and Code Metrics analysis are <a href="https://connect.microsoft.com/VisualStudio/feedback/details/713608/ca0055-silverlight5-business-application-project" target="_blank">broken</a> for Silverlight 5 projects. I find it very disappointing that MS didn’t make sure that all parts of the development tooling surrounding Silverlight 5 was working by the time that Silverlight 5 went RTW. Hopefully these issues will be resolved soon, but one sort of gets the impression that with no more momentum behind Silverlight it might take quite a while <img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-sadsmile" alt="Sad smile" src="http://lh5.ggpht.com/-Up0BSkzsG3s/TzJGacx5mRI/AAAAAAAAAvo/d706VPXINkI/wlEmoticon-sadsmile%25255B2%25255D.png?imgmax=800"></p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com4tag:blogger.com,1999:blog-4775121157402872976.post-11298698854221303692011-06-24T08:31:00.001+02:002011-06-24T08:31:50.928+02:00Elementary, my dear Watson<p><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"> </p> <p><rant> I don’t know about any other .NET developer out there, but I’m finding the <a href="http://www.zdnet.com/blog/microsoft/microsoft-splits-up-its-xaml-team-whats-the-fallout/9807" target="_blank">current</a> <a href="http://www.zdnet.com/blog/microsoft/under-the-windows-8-hood-questions-and-answers-from-the-trenches/9738" target="_blank">speculation</a> with regards to what’s going to happen with vNext of the .NET developer tool stack to be totally frustrating to say the least. This is causing so much angst and damage in the .NET developer community. 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. Yes, I know, all will become crystal clear at the <a href="http://www.zdnet.com/blog/microsoft/microsoft-if-we-build-a-new-developers-conference-will-they-come/9584" target="_blank">BUILD conference</a> somewhere in September, but why didn’t MS keep quiet until then? 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. Why even mention something like “<a href="http://www.zdnet.com/blog/microsoft/windows-8-more-than-just-windows-phone-on-your-pc/9592" target="_blank">HTML 5 and JavaScript is the way to go</a>” with the first <a href="http://www.microsoft.com/presspass/features/2011/jun11/06-01corporatenews.aspx" target="_blank">demo preview of Windows 8</a>. Surely MS should have expected the reaction by developers wanting to know what the future holds for the other technology stacks? Anyway, I hope MS gets this right and that v1 of the next, seemingly <a href="http://www.zdnet.com/blog/microsoft/more-on-microsoft-jupiter-and-what-it-means-for-windows-8/8373" target="_blank">consolidated UX platform</a>, does not set us back another 2/3 years in waiting for it to become a really usable technology stack. </rant></p> <p>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. Alternatively we can just let it be and hope that everything will indeed fall together in a big “ah-hah moment” come September. 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. Elementary indeed.” Time to get some rest before September then <img alt="Disappointed" src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/what_smile.gif"></p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com2tag:blogger.com,1999:blog-4775121157402872976.post-85591950734518641542011-04-11T09:07:00.001+02:002011-04-11T09:17:21.748+02:00Pragma On Key Silverlight Localization<p><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" /> </p> <p>One of the big features that we are adding to Version 5.4 of On Key, <a href="http://www.pragmaworld.net/" target="_blank">Pragma’s</a> Enterprise Asset Management System, is the ability to use the system in different languages.  It seems like the first language we will support in addition to English will be Brazilian Portuguese  to support customers for our <a href="http://www.pragmabrasil.com.br/" target="_blank">Pragma Brazil</a> service company.  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.  In this post I will cover some useful information I discovered in my research.</p> <a name='more'></a> <h2>Static Text</h2> <p>Fortunately we’ve been following the <a href="http://msdn.microsoft.com/en-us/library/cc838238(v=vs.95).aspx" target="_blank">recommended best practice for localizing Silverlight applications</a> by storing all the text that needs to be localized in external resource files.  We currently have around 290 resources files with around 8200 strings that need to be translated from English into other languages.  The resources stored within these files are all static type resources like menu text, captions, tooltips, error messages etc.  I was looking for a solution that would make the process of managing and translating these strings as easy as possible.</p> <p>I’ve been keeping an eye on <a href="http://amanuens.com/" target="_blank">Amanuens</a> since I first read about their localization solution back in 2010, so I headed off to their <a href="http://amanuens.com/" target="_blank">web-site</a> to see how it has matured since the early beta phases.  Amanuens gives you the ability to upload your resource files into the cloud to get translators to translate them into your language of choice.  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.  This is all done via an easy-to-use web-based interface.  The output is the actual translated resource files in a variety of formats of which .NET resource files is one.  Amanuens also has some other really nifty features like a shared <a href="http://support.amanuens.com/TranslationMemory.ashx" target="_blank">Translation Memory</a>, the ability <a href="http://support.amanuens.com/Screenshots.ashx" target="_blank">to attach screenshots</a> to provide context for translations and <a href="http://amanuens.com/Tour.aspx" target="_blank">much more</a>.</p> <p>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.  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.  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.  </p> <h2>Dynamic Text</h2> <p>In addition to the static text, On Key also has a nifty feature called Phrase Translations.  A phrase is defined as a piece of text delimited by the “<strong>{</strong>“ and “<strong>}</strong>” 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 <strong><em>{Check} the {Bearing} </em></strong>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. <strong><em>Inspekteer the Draer</em></strong> if they specified Afrikaans. The technical implementation for these Phrase Translations is actually quite interesting as we utilize the <a href="http://www.sqlclr.net/" target="_blank">SQLCLR</a> to get the best performance possible, but that is a post for another day.</p> <h2>Dynamically loading Resources</h2> <p>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.  Ideally we only want to download the resources for each client’s neutral and language specific cultures.  One <a href="http://msdn.microsoft.com/en-us/library/cc838238%28v=vs.95%29.aspx#Deploy" target="_blank">solution to the problem</a> is to create culture specific XAP files for every language supported.  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.  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.  I then came across <a href="http://www.guysmithferrier.com/post/2010/11/Video-Internationalizing-Silverlight-at-SLUGUK.aspx" target="_blank">this excellent video presentation</a> by Guy Smith-Ferrier on Internationalizing Silverlight applications.  In the presentation he covers a technique whereby he <a href="http://www.guysmithferrier.com/post/2010/10/Building-Localized-XAP-Resource-Files-For-Silverlight-4.aspx" target="_blank">creates separate XAP files using a MSBuild task</a> that contains only the localized resources and not the complete application.  All of this happens <strong>without</strong> having to create separate build configurations in Visual Studio.  He then further illustrates how to use <a href="http://mef.codeplex.com/" target="_blank">MEF</a> to dynamically download the correct culture specific XAP file at run-time when the Silverlight application starts.  </p> <p>This was more to my liking and after spending some time looking at the source code, I implemented something similar in our environment.  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.  As every <a href="http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.aspx" target="_blank">CultureInfo</a> instance has a reference to its <a href="http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.parent.aspx" target="_blank">Parent</a> 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.  Here is some sample C# code that illustrates how to accomplish this:</p> <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"><pre style=" width: 686px; height: 543px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"><div><!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--><span style="color: #008080;"> 1</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> App()
</span><span style="color: #008080;"> 2</span> <span style="color: #000000;"> {
</span><span style="color: #008080;"> 3</span> <span style="color: #000000;"> Startup </span><span style="color: #000000;">+=</span><span style="color: #000000;"> Application_Startup;
</span><span style="color: #008080;"> 4</span> <span style="color: #000000;"> Exit </span><span style="color: #000000;">+=</span><span style="color: #000000;"> Application_Exit;
</span><span style="color: #008080;"> 5</span> <span style="color: #000000;"> UnhandledException </span><span style="color: #000000;">+=</span><span style="color: #000000;"> Application_UnhandledException;
</span><span style="color: #008080;"> 6</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 7</span> <span style="color: #000000;"> InitializeComponent();
</span><span style="color: #008080;"> 8</span> <span style="color: #000000;"> }
</span><span style="color: #008080;"> 9</span> <span style="color: #000000;">
</span><span style="color: #008080;">10</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">void</span><span style="color: #000000;"> Application_Startup(</span><span style="color: #0000FF;">object</span><span style="color: #000000;"> sender, StartupEventArgs e)
</span><span style="color: #008080;">11</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">12</span> <span style="color: #000000;"> var options </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> NinjectSettings {InjectAttribute </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">typeof</span><span style="color: #000000;"> (InjectAttribute)};
</span><span style="color: #008080;">13</span> <span style="color: #000000;"> IocContainer.Kernel </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> StandardKernel(options, </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> IocInfrastructureModule(), </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> IocNavigationModule(), </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> IocServiceModule());
</span><span style="color: #008080;">14</span> <span style="color: #000000;">
</span><span style="color: #008080;">15</span> <span style="color: #000000;"> DownloadLanguageResources(Thread.CurrentThread.CurrentUICulture);
</span><span style="color: #008080;">16</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">17</span> <span style="color: #000000;">
</span><span style="color: #008080;">18</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">void</span><span style="color: #000000;"> DownloadLanguageResources(CultureInfo culture)
</span><span style="color: #008080;">19</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">20</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">string</span><span style="color: #000000;"> xapResourceFilename </span><span style="color: #000000;">=</span><span style="color: #000000;"> String.Format(CultureInfo.InvariantCulture, </span><span style="color: #800000;">"</span><span style="color: #800000;">{0}.{1}.xap</span><span style="color: #800000;">"</span><span style="color: #000000;">, </span><span style="color: #800000;">"</span><span style="color: #800000;">Pragma.OnKey5.Client</span><span style="color: #800000;">"</span><span style="color: #000000;">, culture.Name);
</span><span style="color: #008080;">21</span> <span style="color: #000000;">
</span><span style="color: #008080;">22</span> <span style="color: #000000;"> XapLoader xapLoader </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> XapLoader(xapResourceFilename);
</span><span style="color: #008080;">23</span> <span style="color: #000000;"> xapLoader.Completed </span><span style="color: #000000;">+=</span><span style="color: #000000;"> (s, args) </span><span style="color: #000000;">=></span><span style="color: #000000;">
</span><span style="color: #008080;">24</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">25</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (culture.Parent.IsNeutralCulture)
</span><span style="color: #008080;">26</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">27</span> <span style="color: #000000;"> </span><span style="color: #008000;">//</span><span style="color: #008000;"> Search for user's region neutral resources</span><span style="color: #008000;">
</span><span style="color: #008080;">28</span> <span style="color: #008000;"></span><span style="color: #000000;"> DownloadLanguageResources(culture.Parent);
</span><span style="color: #008080;">29</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">30</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">else</span><span style="color: #000000;">
</span><span style="color: #008080;">31</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">32</span> <span style="color: #000000;"> RootVisual </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> Page();
</span><span style="color: #008080;">33</span> <span style="color: #000000;">
</span><span style="color: #008080;">34</span> <span style="color: #000000;"> </span><span style="color: #008000;">//</span><span style="color: #008000;"> Set the resource to use for all Telerik controls</span><span style="color: #008000;">
</span><span style="color: #008080;">35</span> <span style="color: #008000;"></span><span style="color: #000000;"> LocalizationManager.DefaultResourceManager </span><span style="color: #000000;">=</span><span style="color: #000000;"> Strings.ResourceManager;
</span><span style="color: #008080;">36</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">37</span> <span style="color: #000000;"> };
</span><span style="color: #008080;">38</span> <span style="color: #000000;"> xapLoader.DownloadAsync();
</span><span style="color: #008080;">39</span> <span style="color: #000000;"> }</span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>
<p>You will notice that I’m not using MEF to dynamically download the XAP files, but instead I’m using a custom <strong><em>XapLoader</em></strong> class.  I had two reasons for not using MEF:</p>
<ol>
<li>I quite new to MEF and I couldn’t figure out how to get MEF to dynamically download multiple <strong><em>DeploymentCatalog</em></strong> instances as I traverse the culture tree.  If a reader knows how to do this, please respond in the comments. </li>
<li>I wasn’t interested in the whole MEF discovery mechanism to wire up modules etc.  I only wanted to download the XAP file.  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. </li>
</ol>
<p>Here is the source code for the <strong><em>XapLoader</em></strong> class.  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:</p>
<p></p>
<p> </p>
<p></p>
<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"><pre style=" width: 686px; height: 543px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"><div><!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--><span style="color: #008080;"> 1</span> <span style="color: #000000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;"> 2</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> XAP file loader to dynamically download and load additional XAP resources at run-time
</span><span style="color: #008080;"> 3</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #808080;">
</span><span style="color: #008080;"> 4</span> <span style="color: #808080;"></span><span style="color: #000000;"> [SuppressMessage(</span><span style="color: #800000;">"</span><span style="color: #800000;">Microsoft.Naming</span><span style="color: #800000;">"</span><span style="color: #000000;">, </span><span style="color: #800000;">"</span><span style="color: #800000;">CA1704:IdentifiersShouldBeSpelledCorrectly</span><span style="color: #800000;">"</span><span style="color: #000000;">, MessageId </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">Xap</span><span style="color: #800000;">"</span><span style="color: #000000;">)]
</span><span style="color: #008080;"> 5</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">class</span><span style="color: #000000;"> XapLoader
</span><span style="color: #008080;"> 6</span> <span style="color: #000000;"> {
</span><span style="color: #008080;"> 7</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">readonly</span><span style="color: #000000;"> </span><span style="color: #0000FF;">string</span><span style="color: #000000;"> _xapName;
</span><span style="color: #008080;"> 8</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 9</span> <span style="color: #000000;"> [SuppressMessage(</span><span style="color: #800000;">"</span><span style="color: #800000;">Microsoft.Naming</span><span style="color: #800000;">"</span><span style="color: #000000;">, </span><span style="color: #800000;">"</span><span style="color: #800000;">CA1704:IdentifiersShouldBeSpelledCorrectly</span><span style="color: #800000;">"</span><span style="color: #000000;">, MessageId </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">xap</span><span style="color: #800000;">"</span><span style="color: #000000;">)]
</span><span style="color: #008080;">10</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> XapLoader(</span><span style="color: #0000FF;">string</span><span style="color: #000000;"> xapName)
</span><span style="color: #008080;">11</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">12</span> <span style="color: #000000;"> Check.ArgumentNotNullOrEmptyString(xapName, </span><span style="color: #800000;">"</span><span style="color: #800000;">xapName</span><span style="color: #800000;">"</span><span style="color: #000000;">);
</span><span style="color: #008080;">13</span> <span style="color: #000000;"> _xapName </span><span style="color: #000000;">=</span><span style="color: #000000;"> xapName;
</span><span style="color: #008080;">14</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">15</span> <span style="color: #000000;">
</span><span style="color: #008080;">16</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">event</span><span style="color: #000000;"> EventHandler</span><span style="color: #000000;"><</span><span style="color: #000000;">XapLoadedEventArgs</span><span style="color: #000000;">></span><span style="color: #000000;"> Completed;
</span><span style="color: #008080;">17</span> <span style="color: #000000;">
</span><span style="color: #008080;">18</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">#region</span><span style="color: #000000;"> Methods</span><span style="color: #000000;">
</span><span style="color: #008080;">19</span> <span style="color: #000000;">
</span><span style="color: #008080;">20</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">void</span><span style="color: #000000;"> DownloadAsync()
</span><span style="color: #008080;">21</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">22</span> <span style="color: #000000;"> Uri uri </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> Uri(_xapName, UriKind.Relative);
</span><span style="color: #008080;">23</span> <span style="color: #000000;"> WebClient wc </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> WebClient();
</span><span style="color: #008080;">24</span> <span style="color: #000000;"> wc.OpenReadCompleted </span><span style="color: #000000;">+=</span><span style="color: #000000;"> OnXapLoadingResponse;
</span><span style="color: #008080;">25</span> <span style="color: #000000;"> wc.OpenReadAsync(uri);
</span><span style="color: #008080;">26</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">27</span> <span style="color: #000000;">
</span><span style="color: #008080;">28</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">void</span><span style="color: #000000;"> InitXap(Stream stream)
</span><span style="color: #008080;">29</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">30</span> <span style="color: #000000;"> StreamResourceInfo xapStreamInfo </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> StreamResourceInfo(stream, </span><span style="color: #0000FF;">null</span><span style="color: #000000;">);
</span><span style="color: #008080;">31</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">string</span><span style="color: #000000;"> appManifest </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> StreamReader(System.Windows.Application.GetResourceStream(
</span><span style="color: #008080;">32</span> <span style="color: #000000;"> xapStreamInfo,
</span><span style="color: #008080;">33</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> Uri(</span><span style="color: #800000;">"</span><span style="color: #800000;">AppManifest.xaml</span><span style="color: #800000;">"</span><span style="color: #000000;">, UriKind.Relative)).Stream).ReadToEnd();
</span><span style="color: #008080;">34</span> <span style="color: #000000;">
</span><span style="color: #008080;">35</span> <span style="color: #000000;"> XElement deploy </span><span style="color: #000000;">=</span><span style="color: #000000;"> XDocument.Parse(appManifest).Root;
</span><span style="color: #008080;">36</span> <span style="color: #000000;">
</span><span style="color: #008080;">37</span> <span style="color: #000000;"> List</span><span style="color: #000000;"><</span><span style="color: #000000;">XElement</span><span style="color: #000000;">></span><span style="color: #000000;"> parts </span><span style="color: #000000;">=</span><span style="color: #000000;"> (from assemblyParts </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> deploy.Elements().Elements()
</span><span style="color: #008080;">38</span> <span style="color: #000000;"> select assemblyParts).ToList();
</span><span style="color: #008080;">39</span> <span style="color: #000000;">
</span><span style="color: #008080;">40</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">foreach</span><span style="color: #000000;"> (XElement xe </span><span style="color: #0000FF;">in</span><span style="color: #000000;"> parts)
</span><span style="color: #008080;">41</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">42</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">string</span><span style="color: #000000;"> source </span><span style="color: #000000;">=</span><span style="color: #000000;"> xe.Attribute(</span><span style="color: #800000;">"</span><span style="color: #800000;">Source</span><span style="color: #800000;">"</span><span style="color: #000000;">).Value;
</span><span style="color: #008080;">43</span> <span style="color: #000000;"> AssemblyPart asmPart </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> AssemblyPart();
</span><span style="color: #008080;">44</span> <span style="color: #000000;"> StreamResourceInfo streamInfo </span><span style="color: #000000;">=</span><span style="color: #000000;"> System.Windows.Application.GetResourceStream(
</span><span style="color: #008080;">45</span> <span style="color: #000000;"> xapStreamInfo,
</span><span style="color: #008080;">46</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> Uri(source, UriKind.Relative));
</span><span style="color: #008080;">47</span> <span style="color: #000000;"> asmPart.Load(streamInfo.Stream);
</span><span style="color: #008080;">48</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">49</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">50</span> <span style="color: #000000;">
</span><span style="color: #008080;">51</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">#endregion</span><span style="color: #000000;">
</span><span style="color: #008080;">52</span> <span style="color: #000000;">
</span><span style="color: #008080;">53</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">#region</span><span style="color: #000000;"> Event Handlers</span><span style="color: #000000;">
</span><span style="color: #008080;">54</span> <span style="color: #000000;">
</span><span style="color: #008080;">55</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">void</span><span style="color: #000000;"> OnXapLoadingResponse(</span><span style="color: #0000FF;">object</span><span style="color: #000000;"> sender, OpenReadCompletedEventArgs e)
</span><span style="color: #008080;">56</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">57</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> ((e.Error </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #0000FF;">null</span><span style="color: #000000;">) </span><span style="color: #000000;">&&</span><span style="color: #000000;"> (e.Cancelled </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #0000FF;">false</span><span style="color: #000000;">))
</span><span style="color: #008080;">58</span> <span style="color: #000000;"> InitXap(e.Result);
</span><span style="color: #008080;">59</span> <span style="color: #000000;">
</span><span style="color: #008080;">60</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (Completed </span><span style="color: #000000;">!=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">null</span><span style="color: #000000;">)
</span><span style="color: #008080;">61</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">62</span> <span style="color: #000000;"> XapLoadedEventArgs args </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> XapLoadedEventArgs();
</span><span style="color: #008080;">63</span> <span style="color: #000000;"> args.Error </span><span style="color: #000000;">=</span><span style="color: #000000;"> e.Error;
</span><span style="color: #008080;">64</span> <span style="color: #000000;"> args.Cancelled </span><span style="color: #000000;">=</span><span style="color: #000000;"> e.Cancelled;
</span><span style="color: #008080;">65</span> <span style="color: #000000;"> Completed(</span><span style="color: #0000FF;">this</span><span style="color: #000000;">, args);
</span><span style="color: #008080;">66</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">67</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">68</span> <span style="color: #000000;">
</span><span style="color: #008080;">69</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">#endregion</span><span style="color: #000000;">
</span><span style="color: #008080;">70</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">71</span> <span style="color: #000000;">
</span><span style="color: #008080;">72</span> <span style="color: #000000;"> [SuppressMessage(</span><span style="color: #800000;">"</span><span style="color: #800000;">Microsoft.Naming</span><span style="color: #800000;">"</span><span style="color: #000000;">, </span><span style="color: #800000;">"</span><span style="color: #800000;">CA1704:IdentifiersShouldBeSpelledCorrectly</span><span style="color: #800000;">"</span><span style="color: #000000;">, MessageId </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800000;">"</span><span style="color: #800000;">Xap</span><span style="color: #800000;">"</span><span style="color: #000000;">)]
</span><span style="color: #008080;">73</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">class</span><span style="color: #000000;"> XapLoadedEventArgs : EventArgs
</span><span style="color: #008080;">74</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">75</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">#region</span><span style="color: #000000;"> Properties</span><span style="color: #000000;">
</span><span style="color: #008080;">76</span> <span style="color: #000000;">
</span><span style="color: #008080;">77</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">bool</span><span style="color: #000000;"> Cancelled { </span><span style="color: #0000FF;">get</span><span style="color: #000000;">; </span><span style="color: #0000FF;">set</span><span style="color: #000000;">; }
</span><span style="color: #008080;">78</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> Exception Error { </span><span style="color: #0000FF;">get</span><span style="color: #000000;">; </span><span style="color: #0000FF;">set</span><span style="color: #000000;">; }
</span><span style="color: #008080;">79</span> <span style="color: #000000;">
</span><span style="color: #008080;">80</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">#endregion</span><span style="color: #000000;">
</span><span style="color: #008080;">81</span> <span style="color: #000000;"> }</span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>
<p></p>
<p></p>
<p></p>
<p></p>
<p></p>
<p>Here is an example of the code in action when I start up my browser with Brazilian Portuguese as my preferred browser language:</p>
<p><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" /> </p>
<p>Notice how the original XAP file is downloaded and also the two subsequent request for the language specific and language neutral XAP files.  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.</p>
<h2>Conclusion</h2>
<p>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.  Guy Smith-Ferrier covers a lot of this in his presentation so I highly recommend <a href="http://www.guysmithferrier.com/2010/11/default.aspx" target="_blank">watching the video</a> and/or <a href="http://www.guysmithferrier.com/Downloads/I18NSilverlight.zip" target="_blank">downloading the slides</a>.  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.  Lekker lees <img alt="Wink" src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/wink_smile.gif" /></p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com2tag:blogger.com,1999:blog-4775121157402872976.post-74360863402625995682011-04-04T09:44:00.001+02:002011-04-04T09:44:49.772+02:00Pragma Software Development: Check-in Procedure<p>When working together in a software development team it is important to have a common definition for when something is <a href="http://jamesshore.com/Agile-Book/done_done.html" target="_blank">DONE</a>.  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.  Here is the procedure that we use at Pragma for committing changes into our Team Foundation Source Control repository:</p> <ol> <li>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. </li> <li>Code has been formatted according to our <a href="http://www.jetbrains.com/resharper/features/code_formatting.html" target="_blank">ReSharper Pragma Full Cleanup</a><em></em> profile.  This automatically formats all code to follow the same formatting and layout standards. </li> <li>Code compiles without any compiler warnings. </li> <li>Code adheres to our coding standards - I’ll write more about this in a future post.  We try <a href="http://fromthedevtrenches.blogspot.com/2010/06/c-coding-standards-using-resharper.html" target="_blank">to automate the application</a> of our coding standards (where possible) using tools like ReSharper.  Alternatively, use a <a href="http://csharpguidelines.codeplex.com/" target="_blank">code review checklist</a> to quickly identify areas of concern.  </li> <li>No <a href="http://www.jetbrains.com/resharper/features/code_analysis.html" target="_blank">ReSharper code analysis</a> <strong>Error </strong>or <strong>Warning</strong> violations (i.e. green square in scrollbar). Any violation needs to be identified and agreed upon. <strong>Suggestions </strong>and <strong>Hints</strong> can be ignored if deemed unnecessary. </li> <li>No <a href="http://fromthedevtrenches.blogspot.com/2009/11/fxcop.html" target="_blank">FxCop</a> violations. Any violation needs to be identified, agreed upon and justified using the in-code <a href="http://blogs.msdn.com/b/codeanalysis/archive/2006/03/23/559149.aspx" target="_blank">SuppressMessage attribute</a>.</li> <li>New functionality has been covered by tests and the code coverage has been verified using <a href="http://www.ncover.com/" target="_blank">NCover</a>. </li> <li>Bugs have been covered by tests and verified using NCover. </li> <li>Code adherers to the Logging strategy and the developer has inspected the usefulness of the log statements using <a href="http://fromthedevtrenches.blogspot.com/2010/08/log4view-getting-most-out-of-your.html" target="_blank">Log4View</a>. </li> <li>Code adheres to the Exception handling strategy for managing exceptions. </li> <li>Error Messages and translations have been added to the resource files. </li> <li>The associated TFS work item (development ticket/task) has been updated to reflect the effort involved (actual hours, comments etc.)</li> </ol> <p>Once the code satisfies the above mentioned criteria, the developer runs a <a href="http://www.jetbrains.com/teamcity/features/delayed_commit.html" target="_blank">gated check-in</a> using the <a href="http://www.jetbrains.com/teamcity" target="_blank">TeamCity</a> Visual Studio Plug-in.  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.  Only if all the tests pass will TeamCity commit the changes onto the <a href="http://www.scmpatterns.com/book/pattern-summary.html" target="_blank">Mainline</a>.   The observant reader may have noticed that we don’t do an upfront <a href="http://fromthedevtrenches.blogspot.com/2009/11/code-reviews.html" target="_blank">code review</a>.  As we work <a href="http://fromthedevtrenches.blogspot.com/2011/01/pragma-software-development-team.html" target="_blank">from home for 2-3 days a week</a>, we conduct our code reviews on the checked-in artefacts.  I’ll write more about the code review procedure in a future blog posting.  </p> <p>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.</p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com7tag:blogger.com,1999:blog-4775121157402872976.post-40716539174468918422011-02-05T08:24:00.001+02:002011-02-05T08:35:14.615+02:00Pragma Software Development Tools<p><a href="http://fromthedevtrenches.blogspot.com/2011/01/pragma-software-development-team.html" target="_blank">Last time around</a> I mentioned I would blog about the software development tools we are using.  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  a mind map showing the different software development tools we are using in the different software development disciplines!  Btw, if anybody knows about a decent Live Writer plug-in to insert a thumbnail, be sure to leave me a comment.</p> <p><a href="https://sites.google.com/site/fromthedevtrenches/downloads/PragmaProductsSDLCTools.png?attredirects=0" target="_blank"><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" /></a></p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com14tag:blogger.com,1999:blog-4775121157402872976.post-68100357257526020312011-01-20T09:43:00.001+02:002011-01-20T09:43:03.417+02:00Pragma Software Development Team<p><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" />Following <a href="http://fromthedevtrenches.blogspot.com/2011/01/pragma-on-key-software-development.html" target="_blank">on my intention to blog</a> a bit about our internal development environment here at <a href="http://www.pragmaworld.net" target="_blank">PRAGMA</a>, let’s start with a look at the software development team, how we communicate, where we work and what Software Development Lifecycle we follow.</p> <p> </p> <h2>Team</h2> <p>The software development team has grown quite a bit during the past 2 years.  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.  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.   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.  We believe in a flat structure and in the team taking collective ownership for the solution.  As Development Lead, I share the overall responsibility for the architecture with another senior developer in the team.  We also have a Project Manager/Assistant who helps with administrating the project plan and also currently plays the role of SCRUM Master.</p> <h2>Communication</h2> <p>One of the benefits of working at PRAGMA is that we get to work from home for 2 days a week.  Initially I found it very hard to adapt to not having the whole team co-located.  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.  As the project progressed and things settled in terms of architecture and skills the issue became less of a problem.  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.</p> <p>When working remotely keeping in touch is obviously very important.  We use <a href="http://www.skype.com/intl/en/home" target="_blank">Skype</a> for IM and VOIP calls to interact between individuals and small groups of people.  I specifically mention small groups as we struggled to use Skype for calls that involved the whole team.  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.  Fortunately for us PRAGMA makes use of <a href="http://www.business.att.com/enterprise/Service/unified-communications-enterprise/conferencing-services-enterprise/web-conferencing-enterprise/" target="_blank">Interwise Participant</a> 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.  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.  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.  For simple remote pairing/debugging sessions we find <a href="http://www.hanselman.com/blog/KnowingWhenToAskForHelpMicrosoftSharedView.aspx" target="_blank">Microsoft SharedView</a> to be an excellent solution. </p> <h2>Office Space</h2> <p>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.  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.  Of course there is some good, free coffee as well <img alt="Smile" src="http://messenger.msn.com/MMM2006-04-19_17.00/Resource/emoticons/regular_smile.gif" />  The seating inside the building is based on an open plan setup.  The software development team sit together in what is refer to as the Lab with each person having his/her own small cubicle.  This is a picture of my cubicle in the Lab.</p> <p><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" /> </p> <p>The cubicle barriers are about 1.6 m high and allow you to work without being distracted when somebody walks by your desk.  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.  </p> <p>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.  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.  </p> <p> <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" /> </p> <p>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.</p> <h2>SDLC</h2> <p>Talking about <a href="http://www.scrumalliance.org/" target="_blank">SCRUM</a>, 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.  I’m a firm believer in an agile development methodology and all the disciplines involved with doing agile development so we adopted <a href="http://www.scrumalliance.org/" target="_blank">SCRUM</a>.  We went through quite a few <a href="http://en.wikipedia.org/wiki/Scrum_(development)#Terminology" target="_blank">Sprints</a> trying out the different aspects of SCRUM to find out what works best in our environment.  After starting with 2 week Sprints we eventually settled on 3 weeks as our ideal Sprint length.  We tried <a href="http://www.planningpoker.com/" target="_blank">Planning Poker</a> for a few Sprints but eventually dropped this in favour of just estimating the tasks for a Sprint in Ideal hours.   We had some big debates about using <a href="http://blog.mountaingoatsoftware.com/should-companies-measure-productivity-in-story-points-ideal-days" target="_blank">Story Points versus Ideal Hours </a>and how we should track our Velocity.  We took quite a long time to get a <a href="http://en.wikipedia.org/wiki/Scrum_(development)#Product_backlog" target="_blank">Prioritized Product Backlog</a> 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.   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.  </p> <p>For a start I think we need to break the team into smaller groups that focus on specific functional areas of <a href="http://fromthedevtrenches.blogspot.com/2010/11/pragma-on-key-release-3-milestone.html" target="_blank">On Key</a>.  We can then use a <a href="http://www.scrumalliance.org/articles/46-advice-on-conducting-the-scrum-of-scrums-meeting" target="_blank">Scrum of Scrums</a> meeting to discuss the areas of overlap and integration.  We also need to get better at breaking down the functionality in coarser tasks (or work items).  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.   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.   This might ease the pain of integrating back into the project plan as well.   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.</p> <h2>Sprint</h2> <p>So how does a typical 3-week Sprint look taking into account that we work remotely for about half of the time?  The following 3 week roster gives a quick summary of the high-level activities involved:</p> <table border="1" cellspacing="0" cellpadding="2" width="693"><tbody> <tr> <td valign="top" width="132" align="center">Mon</td> <td valign="top" width="132" align="center">Tue</td> <td valign="top" width="132" align="center">Wed</td> <td valign="top" width="141" align="center">Thu</td> <td valign="top" width="154" align="center">Fri</td> </tr> <tr> <td valign="top" width="132"><strong>At the office</strong> <br />Individual Planning and Design Discussions</td> <td valign="top" width="132"><strong>At the office</strong> <br />Daily Scrum @ 10:00 <br />Daily Build @ 22:00</td> <td valign="top" width="132"><strong>Working remotely</strong> <br />Daily Scrum @ 10:00 <br />Daily Build @ 22:00</td> <td valign="top" width="141"><strong>At the office</strong> <br />Daily Scrum @ 10:00 <br />Daily Build @ 22:00</td> <td valign="top" width="154"><strong>Working remotely</strong> <br />Daily Scrum @ 10:00 <br />Daily Build @ 22:00</td> </tr> <tr> <td valign="top" width="132"><strong>Working Remotely</strong> <br />Daily Scrum @ 10:00 <br />Daily Build @ 22:00</td> <td valign="top" width="132"><strong>At the office</strong> <br />Daily Scrum @ 10:00 <br />Daily Build @ 22:00</td> <td valign="top" width="132"><strong>Working remotely</strong> <br />Daily Scrum @ 10:00 <br />Daily Build @ 22:00</td> <td valign="top" width="141"><strong>At the office</strong> <br />Daily Scrum @ 10:00 <br />Daily Build @ 22:00</td> <td valign="top" width="154"><strong>Working remotely</strong> <br />Daily Scrum @ 10:00 <br />Daily Build @ 22:00</td> </tr> <tr> <td valign="top" width="132"><strong>Working Remotely</strong> <br />Daily Scrum @ 10:00 <br />Daily Build @ 22:00</td> <td valign="top" width="132"><strong>At the office</strong> <br />Daily Scrum @ 10:00 <br />Daily Build @ 22:00</td> <td valign="top" width="132"><strong>Working remotely</strong> <br />Daily Scrum @ 10:00 <br />Daily Build @ 22:00</td> <td valign="top" width="141"><strong>At the office</strong> <br />Daily Scrum @ 10:00 <br />Sprint Build @ 22:00</td> <td valign="top" width="154"><strong>At the office</strong> <br />Retrospective @ 09:00 <br />High level Planning @ 10:00 <br />Demo @ 13:00 <br />Design, Training @ 14:00 <br />Drinks @ 16:00</td> </tr> </tbody></table> <p>Well, I think that’s enough for now about the overall work environment.  In my next post I’ll look at the Development Tools that we are using.</p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com0tag:blogger.com,1999:blog-4775121157402872976.post-33953517518180798222011-01-14T22:33:00.001+02:002011-01-14T22:33:40.009+02:00Pragma On Key Software Development Environment<p>As <a href="http://fromthedevtrenches.blogspot.com/2010/11/pragma-on-key-release-3-milestone.html" target="_blank">I mentioned towards the end of last year</a>, we delivered an important Release 3 milestone of Pragma On Key V5.  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.  For those unfamiliar with PRAGMA and On Key [<a href="http://www.pragmaworld.net/" target="_blank">Source</a>]:</p> <blockquote> <p>PRAGMA is a global engineering company providing <strong>physical asset management improvement services and products</strong> to our clients. We believe that the most important value derived from our service is <strong>peace of mind.</strong> 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.</p> <p><strong>Pragma On Key</strong> is our homegrown <strong>Enterprise Asset Management System (EAMS)</strong>. 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.</p> </blockquote> <p>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.  </p> <p>We currently support two major versions of On Key:</p> <ol> <li>Version 4 – A Windows forms client/server application that runs on top of SQL Server as DBMS.  The application was developed using Delphi and has been in production for quite a few years already. </li> <li>Version 5 – A new web-based solution architected as a RIA application.  It uses Silverlight as presentation technology and a layered server architecture using .NET 4.0 on top of SQL Server as DBMS.   </li> </ol> <p>Both versions support interfacing with other ERP systems like SYSPRO and SAP via custom interfaces that we build.  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.  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.    </p> <p>Besides these cool features in On Key itself, we have also IMO come along way in creating a solid software development environment within PRAGMA.  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.  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.</p> <p>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.  I also want to spend some time writing about the design of some of the core features within On Key.   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:</p> <ol> <li>Work environment – Team Composition, Office Space, SDLC (Scrum), Typical Sprint… </li> <li>Development Tools – Source Control, Build Server, Wiki, Work Item Management… </li> <li>Development Practices – Check-in procedure, Code Reviews, Coding Standards, Code Analysis (Static/Dynamic), Code Generation, TDD… </li> <li>Build Automation – Versioning, Continuous Integration, Continuous Performance Testing, Build Pipelines… </li> <li>Testing – Automated Functional Regression Testing… </li> <li>On Key Architecture – Client Architecture, Server Architecture, Localization, Exception Handling, Logging, Security… </li> <li>On Key Features – Rule Engine, Validation Framework, Background Tasks, Rollout, Synchronization… </li> </ol> <p>This list is quite long!  Time permitting, I’ll try and keep posting on some topic hopefully once a week.  Till later…</p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com1tag:blogger.com,1999:blog-4775121157402872976.post-1640890995486728522011-01-03T16:23:00.001+02:002011-01-03T16:23:53.297+02:00My 2011 Software Development Reading List<p>A wonderful 2011 for all!  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.  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.  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.  So without further ado, here is my list of IT books for 2011 that I want to read:</p> <ol> <li><strong>[Partially Read]</strong> <em>Release It!: Michael T. Nygard</em>  - Excellent advise on getting and keeping your software running in production. </li> <li><strong>[Partially Read]</strong> <em>Architecting Applications for the Enterprise: Dino Esposito, Andrea Saltarello</em> – 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. </li> <li><strong>[Partially Read]</strong> <em>Continuous Delivery: Jez Humble, David Farley</em> – Excellent advise on using build, test and deployment automation to manage your software releases.  We’ve got quite a good deployment environment at work as <a href="http://fromthedevtrenches.blogspot.com/2009/11/continuous-integration-from-theory-to.html" target="_blank">I’m a big fan of continuous integration</a>, but it is always nice to read some further insights from experts to see what areas we can still improve on. </li> <li><em>The Art of Application Performance Monitoring: Ian Molyneaux</em> – Performance monitoring is high on the agenda for our <a href="http://fromthedevtrenches.blogspot.com/2010/11/pragma-on-key-release-3-milestone.html" target="_blank">Enterprise Asset Management System (EAMS)</a>. </li> <li><em>Algorithms In A Nutshell: George Heineman, Gary Pollice & Stanley Selkow</em> – Time to learn and brush up on the Graph, Search, Path finding and Network Flow algorithms.  I’ve got a sneaky suspicion that we are missing out on some opportunities to use better algorithms within our EAMS. </li> <li><em>Pragmatic Thinking and Learning: Andy Hunt</em> – Time to figure out the best way to think about solving problems. </li> <li><em>Growing Software – Proven Strategies for Managing Software Engineers: Louis Testa</em> </li> <li><em>Programming Ruby 1.9 (3rd Edition): Dave Thomas</em> – Lots of people are raving about Ruby and I want to start learning why. </li> <li><em>The Ruby Programming Language: David Flanagan & Yukihiro Masumoto</em> </li> </ol> <p>Happy reading :-)</p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com0tag:blogger.com,1999:blog-4775121157402872976.post-26501142913181072942010-11-30T16:25:00.001+02:002010-11-30T16:27:25.122+02:00Pragma On Key – Release 3 Milestone Reached<p>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 <a href="http://www.pragmaworld.net/" target="_blank">company’s</a> Enterprise Asset Management System (EAMS).  It’s been 30 months of hard work to re-write and extend the system using Silverlight and .NET.  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.  We evaluated Silverlight 4 but due to some unresolved memory issues in the framework we decided to stick with Silverlight 3 for now.  We hope to be upgrading to Silverlight 4 soon here after.</p> <p>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.  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.  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.   I can honestly say that within the 2.5 years we only had one or two isolated incidents with the team dynamics.  I think this is a great testimony to the quality of the people working here at <a href="http://www.pragmaworld.net/" target="_blank">Pragma</a>.</p> <p>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.  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!  We’ve got some real nifty features included in this release and I think customers will enjoy the new web based interface as well.  I hope to be blogging a bit more about this and our internal development environment in the future.  Well done to all involved!</p> <p><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" /></p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com5tag:blogger.com,1999:blog-4775121157402872976.post-34125610790065046902010-11-21T18:29:00.001+02:002010-11-21T18:34:45.061+02:00TransactionScope Fluent Interface<p>During the past 2 weeks I’ve been spending a lot of time investigating the performance of Pragma On Key, our <a href="http://www.pragmaworld.net/" target="_blank">company’s</a> Enterprise Asset Management System (EAMS).  Part of the investigation was to resolve some issues we were encountering with deadlocks occurring for some of the longer running transactions.  We are using the <a href="http://msdn.microsoft.com/en-us/library/ms172152(VS.90).aspx" target="_blank">TransactionScope class</a> added in .NET 2.0 to mark blocks of code in our Application Controllers as participating in a transaction.  Out of the box, the default <a href="http://msdn.microsoft.com/en-us/library/system.transactions.isolationlevel.aspx" target="_blank">IsolationLevel</a> used by new a TransactionScope instance is Serializable.  This ensures the best data integrity by preventing dirty reads, nonrepeatable reads and phantom rows.  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.   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.</p> <p>I’ve always found the different settings of the TransactionScope class to be rather confusing.  I always need to remind myself what the different items of the I<a href="http://msdn.microsoft.com/en-us/library/system.transactions.isolationlevel.aspx" target="_blank">solationLevel</a> and <a href="http://msdn.microsoft.com/en-us/library/system.transactions.transactionscopeoption.aspx" target="_blank">TransactionScopeOption</a> enumerations actually mean.  There is also the tricky scenario where, when passing in a new <a href="http://msdn.microsoft.com/en-us/library/system.transactions.transactionoptions.aspx" target="_blank">TransactionOptions</a> 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.  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.  I’ll start by showing some examples usages of the builder and then conclude with the source code for the builder itself.  </p> <a name='more'></a> <p>The first call on the builder is a method to indicate the transactional behaviour of the scope through using the TransactionScopeOption enumeration.  To start a new transaction:</p> <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"><pre style=" width: 570px; height: 125px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"><div><!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--><span style="color: #008080;">1</span> <span style="color: #008000;">//</span><span style="color: #008000;"> RequiresNew</span><span style="color: #008000;">
</span><span style="color: #008080;">2</span> <span style="color: #008000;"></span><span style="color: #000000;">TransactionScope scope </span><span style="color: #000000;">=</span><span style="color: #000000;"> TransactionScopeBuilder.StartNew();
</span><span style="color: #008080;">3</span> <span style="color: #000000;"></span><span style="color: #008000;">//</span><span style="color: #008000;"> Required</span><span style="color: #008000;">
</span><span style="color: #008080;">4</span> <span style="color: #008000;"></span><span style="color: #000000;">TransactionScope scope </span><span style="color: #000000;">=</span><span style="color: #000000;"> TransactionScopeBuilder.StartOrJoinAmbient();
</span><span style="color: #008080;">5</span> <span style="color: #000000;"></span><span style="color: #008000;">//</span><span style="color: #008000;"> Suppress</span><span style="color: #008000;">
</span><span style="color: #008080;">6</span> <span style="color: #008000;"></span><span style="color: #000000;">TransactionScope scope </span><span style="color: #000000;">=</span><span style="color: #000000;"> TransactionScopeBuilder.IgnoreAmbient(); </span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>
<p></p>
<p>The next step is to then set the TransactionOptions.  To set the Isolation Level, call any of the following methods on the builder:</p>
<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"><pre style=" width: 674px; height: 169px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"><div><!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--><span style="color: #008080;">1</span> <span style="color: #008000;">//</span><span style="color: #008000;"> IsolationLevel.ReadUncommitted</span><span style="color: #008000;">
</span><span style="color: #008080;">2</span> <span style="color: #008000;"></span><span style="color: #000000;">TransactionScope scope </span><span style="color: #000000;">=</span><span style="color: #000000;"> TransactionScopeBuilder.StartNew().AllowDirtyReads();
</span><span style="color: #008080;">3</span> <span style="color: #000000;"></span><span style="color: #008000;">//</span><span style="color: #008000;"> IsolationLevel.ReadCommitted</span><span style="color: #008000;">
</span><span style="color: #008080;">4</span> <span style="color: #008000;"></span><span style="color: #000000;">TransactionScope scope </span><span style="color: #000000;">=</span><span style="color: #000000;"> TransactionScopeBuilder.StartNew().PreventDirtyReads();
</span><span style="color: #008080;">5</span> <span style="color: #000000;"></span><span style="color: #008000;">//</span><span style="color: #008000;"> IsolationLevel.RepeatableRead</span><span style="color: #008000;">
</span><span style="color: #008080;">6</span> <span style="color: #008000;"></span><span style="color: #000000;">TransactionScope scope </span><span style="color: #000000;">=</span><span style="color: #000000;"> TransactionScopeBuilder.StartNew().PreventNonRepeatableReads();
</span><span style="color: #008080;">7</span> <span style="color: #000000;"></span><span style="color: #008000;">//</span><span style="color: #008000;"> IsolationLevel.Serializable</span><span style="color: #008000;">
</span><span style="color: #008080;">8</span> <span style="color: #008000;"></span><span style="color: #000000;">TransactionScope scope </span><span style="color: #000000;">=</span><span style="color: #000000;"> TransactionScopeBuilder.StartNew().PreventPhantomReads(); </span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>
<p></p>
<p>Having the method indicate what scenarios it will allow/prevent makes for easier reading IMO.  Lastly we can set the timeout associated with the transaction by calling any of the following methods on the builder:</p>
<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"><pre style=" width: 681px; height: 80px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"><div><!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--><span style="color: #008080;">1</span> <span style="color: #000000;">TransactionScope scope </span><span style="color: #000000;">=</span><span style="color: #000000;"> TransactionScopeBuilder.StartNew().RunsFor(TimeSpan.FromMinutes(</span><span style="color: #800080;">3</span><span style="color: #000000;">));
</span><span style="color: #008080;">2</span> <span style="color: #000000;">TransactionScope scope </span><span style="color: #000000;">=</span><span style="color: #000000;"> TransactionScopeBuilder.StartNew().RunsForMinutes(</span><span style="color: #800080;">3</span><span style="color: #000000;">);
</span><span style="color: #008080;">3</span> <span style="color: #000000;">TransactionScope scope </span><span style="color: #000000;">=</span><span style="color: #000000;"> TransactionScopeBuilder.StartNew().RunsForSeconds(</span><span style="color: #800080;">180</span><span style="color: #000000;">);</span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>
<p>By defining an <a href="http://msdn.microsoft.com/en-us/library/85w54y0a.aspx" target="_blank">implicit cast operator</a> from my TransactionScopeBuilder to a TransactionScope, I can complete the construction process without having to do any additional method calls as illustrated above.  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:</p>
<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"><pre style=" width: 575px; height: 48px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"><div><!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--><span style="color: #008080;">1</span> <span style="color: #0000FF;">using</span><span style="color: #000000;"> (TransactionScopeBuilder.StartNew().PreventPhantomReads().Instance)</span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>
<p></p>
<p>Putting all of this together, let’s look at the syntax for creating a nested TransactionScope instance:</p>
<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"><pre style=" width: 688px; height: 207px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"><div><!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--><span style="color: #008080;"> 1</span> <span style="color: #0000FF;">using</span><span style="color: #000000;"> (TransactionScopeBuilder.StartNew().PreventPhantomReads().Instance)
</span><span style="color: #008080;"> 2</span> <span style="color: #000000;">{
</span><span style="color: #008080;"> 3</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">using</span><span style="color: #000000;"> (TransactionScope scope </span><span style="color: #000000;">=</span><span style="color: #000000;"> TransactionScopeBuilder.StartOrJoinAmbient()
</span><span style="color: #008080;"> 4</span> <span style="color: #000000;"> .PreventDirtyReads()
</span><span style="color: #008080;"> 5</span> <span style="color: #000000;"> .RunsFor(TimeSpan.FromMinutes(</span><span style="color: #800080;">3</span><span style="color: #000000;">)))
</span><span style="color: #008080;"> 6</span> <span style="color: #000000;"> {
</span><span style="color: #008080;"> 7</span> <span style="color: #000000;"> Assert.That(scope, Is.Not.Null);
</span><span style="color: #008080;"> 8</span> <span style="color: #000000;"> Assert.That(Transaction.Current.IsolationLevel, Is.EqualTo(IsolationLevel.Serializable));
</span><span style="color: #008080;"> 9</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">10</span> <span style="color: #000000;">}</span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>
<p>Some other benefits I get from encapsulating the construction logic in the builder are:</p>
<ol>
<li>Ability to add logging to show when new instances are created and what the settings for the new transaction are. </li>
<li>Ability to enforce my own default settings for constructing new instances through reading values from configuration etc. </li>
<li>Ability to auto-escalate the nested transaction to the IsolationLevel of the ambient transaction.  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. </li>
</ol>
<p>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:</p>
<p></p>
<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"><pre style=" width: 686px; height: 543px;background-color:White;overflow: auto;;font-family:Consolas;font-size:12"><div><!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--><span style="color: #008080;"> 1</span> <span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;"> 2</span> <span style="color: #008000;"></span><span style="color: #808080;">///</span><span style="color: #008000;"> Builder Pattern to create configured </span><span style="color: #808080;"><see cref = "TransactionScope" /></span><span style="color: #008000;"> instances.
</span><span style="color: #008080;"> 3</span> <span style="color: #008000;"></span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #808080;">
</span><span style="color: #008080;"> 4</span> <span style="color: #808080;"></span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">sealed</span><span style="color: #000000;"> </span><span style="color: #0000FF;">class</span><span style="color: #000000;"> TransactionScopeBuilder
</span><span style="color: #008080;"> 5</span> <span style="color: #000000;">{
</span><span style="color: #008080;"> 6</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> ILogger _logger;
</span><span style="color: #008080;"> 7</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> IConfigRegistry _config </span><span style="color: #000000;">=</span><span style="color: #000000;"> ConfigRegistry.Instance;
</span><span style="color: #008080;"> 8</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 9</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">readonly</span><span style="color: #000000;"> </span><span style="color: #0000FF;">bool</span><span style="color: #000000;"> _autoEscalateToAmbientIsolationLevel;
</span><span style="color: #008080;"> 10</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> IsolationLevel _isolationLevel;
</span><span style="color: #008080;"> 11</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">readonly</span><span style="color: #000000;"> </span><span style="color: #0000FF;">bool</span><span style="color: #000000;"> _joinExisting;
</span><span style="color: #008080;"> 12</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">readonly</span><span style="color: #000000;"> TransactionScopeOption _scopeOptions;
</span><span style="color: #008080;"> 13</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> TimeSpan _timeout;
</span><span style="color: #008080;"> 14</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 15</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> TransactionScopeBuilder(TransactionScopeOption scopeOptions, </span><span style="color: #0000FF;">bool</span><span style="color: #000000;"> autoEscalateToAmbientIsolationLevel)
</span><span style="color: #008080;"> 16</span> <span style="color: #000000;"> {
</span><span style="color: #008080;"> 17</span> <span style="color: #000000;"> Check.ArgumentNotNull(scopeOptions, </span><span style="color: #800000;">"</span><span style="color: #800000;">scopeOptions</span><span style="color: #800000;">"</span><span style="color: #000000;">);
</span><span style="color: #008080;"> 18</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 19</span> <span style="color: #000000;"> _scopeOptions </span><span style="color: #000000;">=</span><span style="color: #000000;"> scopeOptions;
</span><span style="color: #008080;"> 20</span> <span style="color: #000000;"> _joinExisting </span><span style="color: #000000;">=</span><span style="color: #000000;"> scopeOptions </span><span style="color: #000000;">==</span><span style="color: #000000;"> TransactionScopeOption.Required;
</span><span style="color: #008080;"> 21</span> <span style="color: #000000;"> _autoEscalateToAmbientIsolationLevel </span><span style="color: #000000;">=</span><span style="color: #000000;"> autoEscalateToAmbientIsolationLevel;
</span><span style="color: #008080;"> 22</span> <span style="color: #000000;"> _isolationLevel </span><span style="color: #000000;">=</span><span style="color: #000000;"> IsolationLevel.ReadCommitted;
</span><span style="color: #008080;"> 23</span> <span style="color: #000000;"> _timeout </span><span style="color: #000000;">=</span><span style="color: #000000;"> Config.DatabaseTransactionTimeout;
</span><span style="color: #008080;"> 24</span> <span style="color: #000000;"> }
</span><span style="color: #008080;"> 25</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 26</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">#region</span><span style="color: #000000;"> Properties</span><span style="color: #000000;">
</span><span style="color: #008080;"> 27</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 28</span> <span style="color: #000000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;"> 29</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Constructs the </span><span style="color: #808080;"><see cref = "TransactionScope" /></span><span style="color: #008000;"> instance.
</span><span style="color: #008080;"> 30</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #008000;">
</span><span style="color: #008080;"> 31</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><returns></returns></span><span style="color: #808080;">
</span><span style="color: #008080;"> 32</span> <span style="color: #808080;"></span><span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> TransactionScope Instance
</span><span style="color: #008080;"> 33</span> <span style="color: #000000;"> {
</span><span style="color: #008080;"> 34</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">get</span><span style="color: #000000;"> { </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> Build(</span><span style="color: #0000FF;">this</span><span style="color: #000000;">); }
</span><span style="color: #008080;"> 35</span> <span style="color: #000000;"> }
</span><span style="color: #008080;"> 36</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 37</span> <span style="color: #000000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;"> 38</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Gets or sets the logger.
</span><span style="color: #008080;"> 39</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #808080;">
</span><span style="color: #008080;"> 40</span> <span style="color: #808080;"></span><span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> ILogger Logger
</span><span style="color: #008080;"> 41</span> <span style="color: #000000;"> {
</span><span style="color: #008080;"> 42</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">get</span><span style="color: #000000;">
</span><span style="color: #008080;"> 43</span> <span style="color: #000000;"> {
</span><span style="color: #008080;"> 44</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (_logger </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #0000FF;">null</span><span style="color: #000000;">)
</span><span style="color: #008080;"> 45</span> <span style="color: #000000;"> {
</span><span style="color: #008080;"> 46</span> <span style="color: #000000;"> _logger </span><span style="color: #000000;">=</span><span style="color: #000000;"> LoggerFactory.GetLogger(</span><span style="color: #0000FF;">typeof</span><span style="color: #000000;">(TransactionScopeBuilder));
</span><span style="color: #008080;"> 47</span> <span style="color: #000000;"> }
</span><span style="color: #008080;"> 48</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 49</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> _logger;
</span><span style="color: #008080;"> 50</span> <span style="color: #000000;"> }
</span><span style="color: #008080;"> 51</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">set</span><span style="color: #000000;"> { _logger </span><span style="color: #000000;">=</span><span style="color: #000000;"> value; }
</span><span style="color: #008080;"> 52</span> <span style="color: #000000;"> }
</span><span style="color: #008080;"> 53</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 54</span> <span style="color: #000000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;"> 55</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Gets or sets the configuration registry.
</span><span style="color: #008080;"> 56</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #008000;">
</span><span style="color: #008080;"> 57</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;"> 58</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Gets or sets the configuration registry.
</span><span style="color: #008080;"> 59</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #808080;">
</span><span style="color: #008080;"> 60</span> <span style="color: #808080;"></span><span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> IConfigRegistry Config
</span><span style="color: #008080;"> 61</span> <span style="color: #000000;"> {
</span><span style="color: #008080;"> 62</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">get</span><span style="color: #000000;"> { </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> _config; }
</span><span style="color: #008080;"> 63</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">set</span><span style="color: #000000;"> { _config </span><span style="color: #000000;">=</span><span style="color: #000000;"> value; }
</span><span style="color: #008080;"> 64</span> <span style="color: #000000;"> }
</span><span style="color: #008080;"> 65</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 66</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> IsolationLevel IsolationLevel
</span><span style="color: #008080;"> 67</span> <span style="color: #000000;"> {
</span><span style="color: #008080;"> 68</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">get</span><span style="color: #000000;"> { </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> _isolationLevel; }
</span><span style="color: #008080;"> 69</span> <span style="color: #000000;"> }
</span><span style="color: #008080;"> 70</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 71</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> TransactionScopeOption ScopeOptions
</span><span style="color: #008080;"> 72</span> <span style="color: #000000;"> {
</span><span style="color: #008080;"> 73</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">get</span><span style="color: #000000;"> { </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> _scopeOptions; }
</span><span style="color: #008080;"> 74</span> <span style="color: #000000;"> }
</span><span style="color: #008080;"> 75</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 76</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> TimeSpan Timeout
</span><span style="color: #008080;"> 77</span> <span style="color: #000000;"> {
</span><span style="color: #008080;"> 78</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">get</span><span style="color: #000000;"> { </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> _timeout; }
</span><span style="color: #008080;"> 79</span> <span style="color: #000000;"> }
</span><span style="color: #008080;"> 80</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 81</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">#endregion</span><span style="color: #000000;">
</span><span style="color: #008080;"> 82</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 83</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">#region</span><span style="color: #000000;"> Methods</span><span style="color: #000000;">
</span><span style="color: #008080;"> 84</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 85</span> <span style="color: #000000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;"> 86</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Creates a new </span><span style="color: #808080;"><see cref = "TransactionScope" /></span><span style="color: #008000;"> that ignores the ambient
</span><span style="color: #008080;"> 87</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> transaction through using </span><span style="color: #808080;"><see cref = "TransactionScopeOption.Suppress" /></span><span style="color: #008000;"> option.
</span><span style="color: #008080;"> 88</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #808080;">
</span><span style="color: #008080;"> 89</span> <span style="color: #808080;"></span><span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> TransactionScopeBuilder IgnoreAmbient()
</span><span style="color: #008080;"> 90</span> <span style="color: #000000;"> {
</span><span style="color: #008080;"> 91</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> TransactionScopeBuilder(TransactionScopeOption.Suppress, </span><span style="color: #0000FF;">false</span><span style="color: #000000;">);
</span><span style="color: #008080;"> 92</span> <span style="color: #000000;"> }
</span><span style="color: #008080;"> 93</span> <span style="color: #000000;">
</span><span style="color: #008080;"> 94</span> <span style="color: #000000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;"> 95</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Creates a new </span><span style="color: #808080;"><see cref = "TransactionScope" /></span><span style="color: #008000;"> that starts a new ambient
</span><span style="color: #008080;"> 96</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> transaction through using </span><span style="color: #808080;"><see cref = "TransactionScopeOption.RequiresNew" /></span><span style="color: #008000;"> option.
</span><span style="color: #008080;"> 97</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #808080;">
</span><span style="color: #008080;"> 98</span> <span style="color: #808080;"></span><span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> TransactionScopeBuilder StartNew()
</span><span style="color: #008080;"> 99</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">100</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> TransactionScopeBuilder(TransactionScopeOption.RequiresNew, </span><span style="color: #0000FF;">false</span><span style="color: #000000;">);
</span><span style="color: #008080;">101</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">102</span> <span style="color: #000000;">
</span><span style="color: #008080;">103</span> <span style="color: #000000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;">104</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Creates a new </span><span style="color: #808080;"><see cref = "TransactionScope" /></span><span style="color: #008000;"> that joins the existing ambient
</span><span style="color: #008080;">105</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> transaction if it exists or alternatively starts a new one through using
</span><span style="color: #008080;">106</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><see cref = "TransactionScopeOption.Required" /></span><span style="color: #008000;"> option.
</span><span style="color: #008080;">107</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #008000;">
</span><span style="color: #008080;">108</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><param name = "autoEscalateToAmbientIsolationLevel"></span><span style="color: #008000;">Flag to indicate whether to automatically use
</span><span style="color: #008080;">109</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> the same </span><span style="color: #808080;"><see cref = "IsolationLevel" /></span><span style="color: #008000;"> as the existing ambient transaction.</span><span style="color: #808080;"></param></span><span style="color: #008000;">
</span><span style="color: #008080;">110</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><exception cref="InvalidOperationException"></span><span style="color: #008000;">
</span><span style="color: #008080;">111</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Thrown for auto escalation when the isolation level requested by nested transaction is
</span><span style="color: #008080;">112</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> finer grained than the existing ambient transaction's isolation level.
</span><span style="color: #008080;">113</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></exception></span><span style="color: #808080;">
</span><span style="color: #008080;">114</span> <span style="color: #808080;"></span><span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> TransactionScopeBuilder StartOrJoinAmbient(</span><span style="color: #0000FF;">bool</span><span style="color: #000000;"> autoEscalateToAmbientIsolationLevel </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">true</span><span style="color: #000000;">)
</span><span style="color: #008080;">115</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">116</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> TransactionScopeBuilder(TransactionScopeOption.Required, autoEscalateToAmbientIsolationLevel);
</span><span style="color: #008080;">117</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">118</span> <span style="color: #000000;">
</span><span style="color: #008080;">119</span> <span style="color: #000000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;">120</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Allow dirty reads using </span><span style="color: #808080;"><see cref = "System.Transactions.IsolationLevel.ReadUncommitted" /></span><span style="color: #008000;">
</span><span style="color: #008080;">121</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #808080;">
</span><span style="color: #008080;">122</span> <span style="color: #808080;"></span><span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> TransactionScopeBuilder AllowDirtyReads()
</span><span style="color: #008080;">123</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">124</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> SetIsolationLevel(IsolationLevel.ReadUncommitted);
</span><span style="color: #008080;">125</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">126</span> <span style="color: #000000;">
</span><span style="color: #008080;">127</span> <span style="color: #000000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;">128</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Prevent dirty reads using </span><span style="color: #808080;"><see cref = "System.Transactions.IsolationLevel.ReadCommitted" /></span><span style="color: #008000;">
</span><span style="color: #008080;">129</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #808080;">
</span><span style="color: #008080;">130</span> <span style="color: #808080;"></span><span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> TransactionScopeBuilder PreventDirtyReads()
</span><span style="color: #008080;">131</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">132</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> SetIsolationLevel(IsolationLevel.ReadCommitted);
</span><span style="color: #008080;">133</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">134</span> <span style="color: #000000;">
</span><span style="color: #008080;">135</span> <span style="color: #000000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;">136</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Prevent non-repeatable reads using </span><span style="color: #808080;"><see cref = "System.Transactions.IsolationLevel.RepeatableRead" /></span><span style="color: #008000;">
</span><span style="color: #008080;">137</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #808080;">
</span><span style="color: #008080;">138</span> <span style="color: #808080;"></span><span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> TransactionScopeBuilder PreventNonRepeatableReads()
</span><span style="color: #008080;">139</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">140</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> SetIsolationLevel(IsolationLevel.RepeatableRead);
</span><span style="color: #008080;">141</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">142</span> <span style="color: #000000;">
</span><span style="color: #008080;">143</span> <span style="color: #000000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;">144</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Prevent phantom reads using </span><span style="color: #808080;"><see cref = "System.Transactions.IsolationLevel.Serializable" /></span><span style="color: #008000;">
</span><span style="color: #008080;">145</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #808080;">
</span><span style="color: #008080;">146</span> <span style="color: #808080;"></span><span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> TransactionScopeBuilder PreventPhantomReads()
</span><span style="color: #008080;">147</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">148</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> SetIsolationLevel(IsolationLevel.Serializable);
</span><span style="color: #008080;">149</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">150</span> <span style="color: #000000;">
</span><span style="color: #008080;">151</span> <span style="color: #000000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;">152</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Sets the timeout for the transaction in minutes.
</span><span style="color: #008080;">153</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #008000;">
</span><span style="color: #008080;">154</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><param name = "minutes"></span><span style="color: #008000;">The minutes to run before timeout.</span><span style="color: #808080;"></param></span><span style="color: #808080;">
</span><span style="color: #008080;">155</span> <span style="color: #808080;"></span><span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> TransactionScopeBuilder RunsForMinutes(</span><span style="color: #0000FF;">int</span><span style="color: #000000;"> minutes)
</span><span style="color: #008080;">156</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">157</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> RunsFor(TimeSpan.FromMinutes(minutes));
</span><span style="color: #008080;">158</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">159</span> <span style="color: #000000;">
</span><span style="color: #008080;">160</span> <span style="color: #000000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;">161</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Sets the timeout for the transaction in seconds.
</span><span style="color: #008080;">162</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #008000;">
</span><span style="color: #008080;">163</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><param name = "seconds"></span><span style="color: #008000;">The seconds to run before timeout.</span><span style="color: #808080;"></param></span><span style="color: #808080;">
</span><span style="color: #008080;">164</span> <span style="color: #808080;"></span><span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> TransactionScopeBuilder RunsForSeconds(</span><span style="color: #0000FF;">int</span><span style="color: #000000;"> seconds)
</span><span style="color: #008080;">165</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">166</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> RunsFor(TimeSpan.FromSeconds(seconds));
</span><span style="color: #008080;">167</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">168</span> <span style="color: #000000;">
</span><span style="color: #008080;">169</span> <span style="color: #000000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;">170</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Sets the timeout for the transaction.
</span><span style="color: #008080;">171</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #008000;">
</span><span style="color: #008080;">172</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><param name = "timeout"></span><span style="color: #008000;">The timeout.</span><span style="color: #808080;"></param></span><span style="color: #808080;">
</span><span style="color: #008080;">173</span> <span style="color: #808080;"></span><span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> TransactionScopeBuilder RunsFor(TimeSpan timeout)
</span><span style="color: #008080;">174</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">175</span> <span style="color: #000000;"> _timeout </span><span style="color: #000000;">=</span><span style="color: #000000;"> timeout;
</span><span style="color: #008080;">176</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> </span><span style="color: #0000FF;">this</span><span style="color: #000000;">;
</span><span style="color: #008080;">177</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">178</span> <span style="color: #000000;">
</span><span style="color: #008080;">179</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> TransactionScope Build(TransactionScopeBuilder scopeBuilder)
</span><span style="color: #008080;">180</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">181</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (Logger.IsDebugEnabled)
</span><span style="color: #008080;">182</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">183</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (scopeBuilder.ScopeOptions </span><span style="color: #000000;">==</span><span style="color: #000000;"> TransactionScopeOption.Required </span><span style="color: #000000;">&&</span><span style="color: #000000;"> Transaction.Current </span><span style="color: #000000;">!=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">null</span><span style="color: #000000;">)
</span><span style="color: #008080;">184</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">185</span> <span style="color: #000000;"> Logger.Debug(</span><span style="color: #800000;">"</span><span style="color: #800000;">Creating nested transaction (Scope={0};Isolation Level={1};Timeout={2}).</span><span style="color: #800000;">"</span><span style="color: #000000;">, scopeBuilder.ScopeOptions, scopeBuilder.IsolationLevel, scopeBuilder.Timeout);
</span><span style="color: #008080;">186</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">187</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">else</span><span style="color: #000000;">
</span><span style="color: #008080;">188</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">189</span> <span style="color: #000000;"> Logger.Debug(</span><span style="color: #800000;">"</span><span style="color: #800000;">Creating new transaction (Scope={0};Isolation Level={1};Timeout={2}).</span><span style="color: #800000;">"</span><span style="color: #000000;">, scopeBuilder.ScopeOptions, scopeBuilder.IsolationLevel, scopeBuilder.Timeout);
</span><span style="color: #008080;">190</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">191</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">192</span> <span style="color: #000000;">
</span><span style="color: #008080;">193</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> TransactionScope(scopeBuilder.ScopeOptions, </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> TransactionOptions
</span><span style="color: #008080;">194</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">195</span> <span style="color: #000000;"> IsolationLevel </span><span style="color: #000000;">=</span><span style="color: #000000;"> scopeBuilder.IsolationLevel,
</span><span style="color: #008080;">196</span> <span style="color: #000000;"> Timeout </span><span style="color: #000000;">=</span><span style="color: #000000;"> scopeBuilder.Timeout
</span><span style="color: #008080;">197</span> <span style="color: #000000;"> });
</span><span style="color: #008080;">198</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">199</span> <span style="color: #000000;">
</span><span style="color: #008080;">200</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">private</span><span style="color: #000000;"> TransactionScopeBuilder SetIsolationLevel(IsolationLevel requiredLevel)
</span><span style="color: #008080;">201</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">202</span> <span style="color: #000000;"> IsolationLevel acceptedLevel </span><span style="color: #000000;">=</span><span style="color: #000000;"> requiredLevel;
</span><span style="color: #008080;">203</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (_joinExisting </span><span style="color: #000000;">&&</span><span style="color: #000000;"> _autoEscalateToAmbientIsolationLevel </span><span style="color: #000000;">&&</span><span style="color: #000000;"> Transaction.Current </span><span style="color: #000000;">!=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">null</span><span style="color: #000000;">)
</span><span style="color: #008080;">204</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">205</span> <span style="color: #000000;"> </span><span style="color: #008000;">//</span><span style="color: #008000;"> Can only escalate to ambient level if the required level is a less-fine grained lock
</span><span style="color: #008080;">206</span> <span style="color: #008000;"> </span><span style="color: #008000;">//</span><span style="color: #008000;"> IsolationLevel Enum values: Serializable = 0; RepeatableRead = 1; ReadCommitted = 2; ReadUncommitted = 3</span><span style="color: #008000;">
</span><span style="color: #008080;">207</span> <span style="color: #008000;"></span><span style="color: #000000;"> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (requiredLevel </span><span style="color: #000000;">>=</span><span style="color: #000000;"> Transaction.Current.IsolationLevel)
</span><span style="color: #008080;">208</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">209</span> <span style="color: #000000;"> acceptedLevel </span><span style="color: #000000;">=</span><span style="color: #000000;"> Transaction.Current.IsolationLevel;
</span><span style="color: #008080;">210</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (Logger.IsDebugEnabled </span><span style="color: #000000;">&&</span><span style="color: #000000;"> requiredLevel </span><span style="color: #000000;">></span><span style="color: #000000;"> Transaction.Current.IsolationLevel)
</span><span style="color: #008080;">211</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">212</span> <span style="color: #000000;"> Logger.Debug(</span><span style="color: #800000;">"</span><span style="color: #800000;">Building a nested transaction (Isolation Level={0}) that will auto escalate to the Ambient transaction (Isolation Level={1})</span><span style="color: #800000;">"</span><span style="color: #000000;">, requiredLevel, acceptedLevel);
</span><span style="color: #008080;">213</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">214</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">215</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">else</span><span style="color: #000000;">
</span><span style="color: #008080;">216</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">217</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">throw</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> ArgumentException(</span><span style="color: #0000FF;">string</span><span style="color: #000000;">.Format(CultureInfo.InvariantCulture, </span><span style="color: #800000;">"</span><span style="color: #800000;">TransactionScope could not be auto escalated. Requested level = {0}, Ambient Level = {1}</span><span style="color: #800000;">"</span><span style="color: #000000;">, requiredLevel, Transaction.Current.IsolationLevel));
</span><span style="color: #008080;">218</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">219</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">220</span> <span style="color: #000000;"> _isolationLevel </span><span style="color: #000000;">=</span><span style="color: #000000;"> acceptedLevel;
</span><span style="color: #008080;">221</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> </span><span style="color: #0000FF;">this</span><span style="color: #000000;">;
</span><span style="color: #008080;">222</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">223</span> <span style="color: #000000;">
</span><span style="color: #008080;">224</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">#endregion</span><span style="color: #000000;">
</span><span style="color: #008080;">225</span> <span style="color: #000000;">
</span><span style="color: #008080;">226</span> <span style="color: #000000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><summary></span><span style="color: #008000;">
</span><span style="color: #008080;">227</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> Performs an implicit conversion from
</span><span style="color: #008080;">228</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><see cref = "Pragma.OnKey.Core.TransactionScopeBuilder" /></span><span style="color: #008000;"> to
</span><span style="color: #008080;">229</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><see cref = "System.Transactions.TransactionScope" /></span><span style="color: #008000;"> by building the actual instance.
</span><span style="color: #008080;">230</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"></summary></span><span style="color: #008000;">
</span><span style="color: #008080;">231</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><param name = "scopeBuilder"></span><span style="color: #008000;">The scope builder.</span><span style="color: #808080;"></param></span><span style="color: #008000;">
</span><span style="color: #008080;">232</span> <span style="color: #008000;"> </span><span style="color: #808080;">///</span><span style="color: #008000;"> </span><span style="color: #808080;"><returns></span><span style="color: #008000;">The result of the conversion.</span><span style="color: #808080;"></returns></span><span style="color: #808080;">
</span><span style="color: #008080;">233</span> <span style="color: #808080;"></span><span style="color: #000000;"> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> </span><span style="color: #0000FF;">implicit</span><span style="color: #000000;"> </span><span style="color: #0000FF;">operator</span><span style="color: #000000;"> TransactionScope(TransactionScopeBuilder scopeBuilder)
</span><span style="color: #008080;">234</span> <span style="color: #000000;"> {
</span><span style="color: #008080;">235</span> <span style="color: #000000;"> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> Build(scopeBuilder);
</span><span style="color: #008080;">236</span> <span style="color: #000000;"> }
</span><span style="color: #008080;">237</span> <span style="color: #000000;">}
</span><span style="color: #008080;">238</span> <span style="color: #000000;"></span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>
<p></p>
<p>Hope you find this useful for helping you manage your own TransactionScope instances!</p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com1tag:blogger.com,1999:blog-4775121157402872976.post-63099474771645621502010-09-30T21:23:00.001+02:002010-09-30T21:23:21.403+02:00Understanding MSIL Memory Leaks<p>We are using a custom <em>RuntimeDataBuilder</em> 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 "DataSet like" 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.</p> <p>I’m currently trying to figure out how the memory management for these custom dynamic types work.  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.  From <a href="http://msdn.microsoft.com/en-us/magazine/cc163491.aspx">this article on MSDN</a> 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.  This opens up a whole new can of worms for inter AppDomain communication which I would rather avoid.</p> <p>So my question is any of my readers can shed some more light on this topic.  Is my assumption correct or is there another way of reclaiming the memory?  I also posted <a href="http://stackoverflow.com/questions/3831901/msil-memory-leaks" target="_blank">the question to StackOverflow</a> if you are interested in checking out the responses over there.  Thx :-)</p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com2tag:blogger.com,1999:blog-4775121157402872976.post-79776994134832606372010-09-01T07:48:00.001+02:002010-09-01T07:48:40.075+02:00Ultimate .NET Development Tools 2010 Edition<p>Here is my updated 2010 list of development tools that I prefer to use when doing .NET development.  I specifically do not include any third party control/report libraries.</p> <h2>Categories</h2> <ul> <li>IDE = Develop/generate/refactor code within the VS IDE or separate IDE  </li> <li>SCM = Software Configuration Management (Source Control etc.) </li> <li>TDD = Test Driven Development <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" /> </li> <li>DBMS = Database Management Systems </li> <li>CI = Continuous Integration </li> <li>FR = Frameworks (Persistence, AOP, Inversion of Control, Logging etc.) </li> <li>UT = Utility Tools </li> <li>CA = Code Analysis (Static + Dynamic) </li> <li>TC = Team Collaboration (Bug tracking, Project management etc.) </li> <li>MD = Modelling </li> <li>QA = Testing Tools </li> <li>DP = Deployment (Installations etc.) </li> </ul> <h2> </h2> <h2>Tools</h2> * = free/open source <br /> <ol> <li>[IDE] <a href="http://msdn2.microsoft.com/en-us/vstudio/default.aspx" target="_blank">Visual Studio 2010 Premium Edition</a> </li> <li>[IDE] <a href="http://www.jetbrains.com/resharper" target="_blank">ReSharper</a> for refactoring, unit test runner and so much more </li> <li>[IDE] <a href="http://www.codesmithtools.com/" target="_blank">CodeSmith</a> for generating code.  Also consider T4 with <a href="http://www.visualt4.com/" target="_blank">Clarius’s Visual T4</a> Editor.   </li> <li>[IDE]* <a href="http://submain.com/products/ghostdoc.aspx" target="_blank">GhostDoc</a> for inserting xml code comments </li> <li>[IDE] <a href="http://www.altova.com/" target="_blank">Altova Xml Suite</a> for any xml related work.  <a href="http://www.wmhelp.com/" target="_blank">XmlPad</a> is the best, free alternative I know of. </li> <li>[DBMS] <a href="http://www.microsoft.com/sql/" target="_blank">SqlServer 2008</a> for DBMS </li> <li>[SCM]* <a href="http://subversion.tigris.org/" target="_blank">Subversion</a> for source control </li> <li>[SCM]* <a href="http://tortoisesvn.tigris.org/" target="_blank">TortoiseSVN</a> as windows shell extension for Subversion </li> <li>[SCM] <a href="http://tortoisesvn.tigris.org/" target="_blank">VisualSVN</a> for integration of TortoiseSVN into VS.  <a href="http://ankhsvn.open.collab.net/" target="_blank">AnkhSVN</a> is the best, free alternative I know of. </li> <li>[SCM]* <a href="http://kdiff3.sourceforge.net/" target="_blank">KDiff3</a> for merging </li> <li>[TDD]* <a href="http://www.nunit.com/" target="_blank">NUnit</a> as preferred xUnit testing framework </li> <li>[TDD]* <a href="http://code.google.com/p/moq/" target="_blank">moq</a> as mock framework. </li> <li>[TDD] <a href="http://www.ncover.com/" target="_blank">NCover</a> for code coverage stats </li> <li>[CI]* <a href="http://www.jetbrains.com/teamcity" target="_blank">TeamCity</a> as build server </li> <li>[CI]* <a href="http://msbuildextensionpack.codeplex.com/" target="_blank">MSBuild Extension Pack</a> for additional MSBuild tasks. </li> <li>[FR]* <a href="http://logging.apache.org/log4net/">log4net</a> as logging framework.  Also see <a href="http://www.log4view.com/" target="_blank">Log4View</a> for an <a href="http://fromthedevtrenches.blogspot.com/2010/08/log4view-getting-most-out-of-your.html" target="_blank">excellent UI</a> for the log files. </li> <li>[FR]* <a href="http://www.antlr.org/" target="_blank">ANTLR</a> and <a href="http://www.antlr.org/works/index.html" target="_blank">ANTLRWorks</a> for creating custom DSL’s. </li> <li>[FR] <a href="http://www.sharpcrafters.com/" target="_blank">PostSharp</a> as Aspect Oriented Programming framework </li> <li>[FR]* <a href="http://ninject.org/" target="_blank">Ninject</a> as IoC container </li> <li>[FR] <a href="http://www.mindscape.co.nz/products/LightSpeed/default.aspx" target="_blank">MindScape LightSpeed</a> as my Object-Relational-Mapper.  <a href="http://www.nhibernate.org/" target="_blank">NHibernate</a> is the best free alternative I’m aware of.  </li> <li>[UT]* <a href="http://www.red-gate.com/products/reflector/index.htm" target="_blank">Reflector</a> to drill down to the guts of any code library (also check-out the <a href="http://www.codeplex.com/reflectoraddins" target="_blank">nice plug-ins</a>) </li> <li>[UT] <a href="http://firstfloorsoftware.com/silverlightspy/" target="_blank">Silverlight Spy</a> to dissect any Silverlight application. </li> <li>[UT] <a href="http://www.regexbuddy.com/" target="_blank">RegexBuddy</a> for managing those difficult regular expressions.  <a href="http://tools.osherove.com/CoolTools/Regulator/tabid/185/Default.aspx" target="_blank">Regulator</a> is the best, free alternative I know of.  </li> <li>[UT]* <a href="http://www.linqpad.net/" target="_blank">LINQPad</a> as a easy way to query SQL databases using LINQ and as a general scratchpad application to test C#/VB.NET code snippets. </li> <li>[UT]* <a href="http://www.fiddlertool.com/" target="_blank">Fiddler</a> to debug all your HTTP traffic in IE.   Also see the <a href="http://blogs.msdn.com/nexpert/" target="_blank">neXpert plugin</a> for monitoring performance problems. </li> <li>[UT]* <a href="http://www.getfirebug.com/" target="_blank">Firebug</a> to assist with testing web applications running in Firefox. Also see <a href="http://developer.yahoo.com/yslow/" target="_blank">YSlow</a> add-on for performance testing and <a href="https://addons.mozilla.org/en-US/firefox/addon/60" target="_blank">Web Developer</a> add-on for additional Firefox web development tools. </li> <li>[CA]* <a href="http://msdn.microsoft.com/en-us/library/bb429476(VS.80).aspx" target="_blank">FxCop</a> to enforce .NET coding guidelines </li> <li>[CA] <a href="http://www.ndepend.com/" target="_blank">NDepend</a> to get all the static code metrics I'd ever want </li> <li>[CA] <a href="http://www.red-gate.com/products/ants_profiler/index.htm" target="_blank">ANTS Profiler</a> for performance and memory profiling </li> <li>[MD] <a href="http://www.sparxsystems.com/" target="_blank">Enterprise Architect</a> to do UML Modelling and Model Driven Design if required. Alternatively use Visio with these <a href="http://www.softwarestencils.com/uml/index.html">simple templates</a>.  </li> <li>[MD]* <a href="http://freemind.sourceforge.net/">FreeMind</a> as mind mapping tool </li> <li>[TC]* <a href="http://www.screwturn.eu/" target="_blank">ScrewTurn Wiki</a> for team collaboration </li> <li>[QA]* <a href="http://www.soapui.org/" target="_blank">Eviware soapUI</a> for functional and load testing of SOA web services </li> <li>[QA]* <a href="http://www.telerik.com/products/web-testing-tools/webaii-framework-features.aspx" target="_blank">Telerik WebAii Testing Framework</a> for automated regression testing of Web 2.0 apps </li> <li>[DP]* <a href="http://wix.sourceforge.net/">Windows Installer XML (WiX)</a> for creating Windows Installers </li> </ol> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com3tag:blogger.com,1999:blog-4775121157402872976.post-52135294587237883072010-08-31T15:19:00.001+02:002010-08-31T15:19:13.433+02:00Threading in C# – Free E-book Updated<p><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" /> This is just a quick post to highlight the fact that Joseph Albahari, author of the excellent <a href="http://www.linqpad.net/" target="_blank">LINQPad</a> and <a href="http://www.albahari.com/nutshell/" target="_blank">C# 4.0 In A Nutshell</a> book, has recently updated hits free <a href="http://www.albahari.com/threading/" target="_blank">Threading in C# e-book</a>.  The e-book contains some really great, concise content on all the latest threading related topics in .NET.  The latest version includes coverage of new .NET 4.0 constructs like ThreadLocal<T> and Lazy<T> as well as a whole chapter dedicated to the new Parallel Programming extensions to the .NET framework.  Highly recommended!</p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com0tag:blogger.com,1999:blog-4775121157402872976.post-4427577434785123842010-08-29T14:55:00.001+02:002010-08-29T14:58:49.740+02:00Log4View – Getting the most out of your log4net/log4j log files<p>If you are using <a href="http://logging.apache.org/log4net/index.html">log4net</a> or <a href="http://logging.apache.org/log4j/1.2/">log4j</a> for writing log files, do yourself a favour and get the whole team and production support a copy of <a href="http://www.log4view.com/">Log4View</a> as soon as possible.  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.  Need to monitor your servers remotely as they are running?  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.  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).  </p> <p>One of the most powerful features IMO is the grouping feature in the message view.  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.  Simply drag the columns you want to group by into the Group By area above the grid:</p> <p><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" /> </p> <p>This specific grouping allows us to easily inspect the separate requests associated with a certain user in the system. Highly recommended!</p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com0tag:blogger.com,1999:blog-4775121157402872976.post-66216918801965075182010-08-29T00:27:00.001+02:002010-08-29T00:27:43.510+02:00RunSharp – IL Generation for Dummies<p>We’ve been doing some interesting work the past 2-3 weeks on creating a Rule Engine for <a href="http://www.pragmaworld.net">our company’s</a> flagship product, On Key.  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.  This allows us tremendous flexibility in that end-users are able to specify under which conditions certain actions should occur within the system.  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.   </p> <p>Before heading off to create our own custom solution, we did some research to consider possible solutions to solving the same kind of problem.  Some of the solutions we came across were:</p> <ol> <li><a href="http://flee.codeplex.com/">Flee</a></li> <li><a href="http://ncalc.codeplex.com/">NCalc</a></li> <li><a href="http://irony.codeplex.com/">Irony</a></li> <li><a href="http://blogs.msdn.com/b/csharpfaq/archive/2009/09/14/generating-dynamic-methods-with-expression-trees-in-visual-studio-2010.aspx">Dynamic method generation using Expression Trees</a> </li> </ol> <p>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.  Setting up the grammar using the excellent <a href="http://www.antlr.org/">ANTLR</a> and <a href="http://www.antlr.org/works/index.html">ANTLRWorks</a> was quite easy to do.  ANTLR takes care of <a href="http://www.antlr.org/wiki/display/ANTLR3/Antlr+3+CSharp+Target">generating the C# code</a> that will do the lexing, parsing and type checking of the rules entered by the user.  Thereafter we moved onto the run-time evaluation/compilation of the rules represented in the <a href="http://en.wikipedia.org/wiki/Abstract_syntax_tree">Abstract Syntax Tree</a> created by ANTLR.  For this purpose, we created 3 tree walkers/visitors on our AST to compare against each other:</p> <ol> <li>Interpreter – Evaluate the rules dynamically as we walk the AST</li> <li>C# Code Generator – Walk the tree and generate C# code that is compiled using the C# compiler into an assembly</li> <li>IL Code Generator – Walk the tree and generate dynamic IL code in memory</li> </ol> <a name='more'></a> <h2>Interpreter</h2> <p>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.  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.  The obvious down side of this solution is the performance overhead compared to compiled C# code.</p> <h2>C# Code Generator</h2> <p>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.  The downside however is that you cannot unload an assembly out of a .NET AppDomain.  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.  This is a technique used by the excellent <a href="http://www.csscript.net/index.html">CS-Script</a> to evaluate C# scripts at run-time.  You also need FullTrust permissions to launch the C# compiler at run-time, which is problematic for our Silverlight IIS hosted application.</p> <h2>IL Code Generator</h2> <p>The main benefit of writing a <a href="http://msdn.microsoft.com/en-us/library/system.reflection.emit.aspx">IL generator</a> 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 <a href="http://msdn.microsoft.com/en-us/library/system.reflection.emit.dynamicmethod.aspx">DynamicMethod</a> from memory when rule changes are made by the end users and the rules therefore need to be recompiled.  However, <a href="http://ayende.com/Blog/archive/2006/08/13/ReflectionEmitVsCodeDOM.aspx">generating IL directly is notoriously difficult</a> and error-prone.  Our immediate concerns were for the technical complexities of managing this solution going forward.  That was until, we discovered <a href="http://code.google.com/p/runsharp/">RunSharp</a>.  We came across RunSharp in this <a href="http://www.codeproject.com/KB/dotnet/runsharp.aspx">CodeProject article</a>.  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.  To illustrate, let me take an example of C# rule generated by the C# Code Generator we created and illustrate the equivalent RunSharp code.</p> <p><strong><u>C# Code</u></strong></p> <p> <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"><pre style="background-color:White;overflow: auto;;font-family:Consolas;font-size:12"><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> </span><span style="color: #0000FF;">bool</span><span style="color: #000000;"> Rule2(IOptionValueProvider options)
{
</span><span style="color: #008000;">//</span><span style="color: #008000;"> "CA_FIL_STE_LIFTING_UNIT = 'WITH FIL STE LIFTING UNIT'"</span><span style="color: #008000;">
</span><span style="color: #000000;">
</span><span style="color: #0000FF;">return</span><span style="color: #000000;"> String.Compare(options.GetOptionValueAsString(</span><span style="color: #800080;">1782</span><span style="color: #000000;">), </span><span style="color: #800000;">"</span><span style="color: #800000;">WITH FIL STE LIFTING UNIT</span><span style="color: #800000;">"</span><span style="color: #000000;">, StringComparison.OrdinalIgnoreCase) </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">;
}
</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>
</p>
<p><strong><u>IL Code</u></strong></p>
<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"><pre style="background-color:#FFFFFF;overflow: auto;;font-family:Consolas;font-size:12"><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> </span><span style="color: #0000FF;">void</span><span style="color: #000000;"> Rule2CIL(TypeGen typeGen)
{
</span><span style="color: #008000;">//</span><span style="color: #008000;"> "CA_FIL_STE_LIFTING_UNIT = 'WITH FIL STE LIFTING UNIT'"</span><span style="color: #008000;">
</span><span style="color: #000000;">
CodeGen g </span><span style="color: #000000;">=</span><span style="color: #000000;"> typeGen.Public.Static.Method(</span><span style="color: #0000FF;">typeof</span><span style="color: #000000;"> (</span><span style="color: #0000FF;">bool</span><span style="color: #000000;">), </span><span style="color: #800000;">"</span><span style="color: #800000;">Rule2</span><span style="color: #800000;">"</span><span style="color: #000000;">).Parameter(</span><span style="color: #0000FF;">typeof</span><span style="color: #000000;"> (IOptionValueProvider), </span><span style="color: #800000;">"</span><span style="color: #800000;">options</span><span style="color: #800000;">"</span><span style="color: #000000;">);
{
Operand result </span><span style="color: #000000;">=</span><span style="color: #000000;"> Static.Invoke(</span><span style="color: #0000FF;">typeof</span><span style="color: #000000;"> (String), </span><span style="color: #800000;">"</span><span style="color: #800000;">Compare</span><span style="color: #800000;">"</span><span style="color: #000000;">, g.Arg(</span><span style="color: #800000;">"</span><span style="color: #800000;">options</span><span style="color: #800000;">"</span><span style="color: #000000;">).Invoke(</span><span style="color: #800000;">"</span><span style="color: #800000;">GetOptionValueAsString</span><span style="color: #800000;">"</span><span style="color: #000000;">, </span><span style="color: #800080;">1782</span><span style="color: #000000;">), </span><span style="color: #800000;">"</span><span style="color: #800000;">WITH FIL STE LIFTING UNIT</span><span style="color: #800000;">"</span><span style="color: #000000;">, StringComparison.OrdinalIgnoreCase) </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">;
g.Return(result);
}
}</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>
<p>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.  RunSharp is able to provide us with such an API through the judicious use of implicit type casting and operator overloading.  Let’s consider a more complex rule involving multiple operands:</p>
<p><strong><u>C# Code</u></strong></p>
<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"><pre style="background-color:#FFFFFF;overflow: auto;;font-family:Consolas;font-size:12"><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> </span><span style="color: #0000FF;">bool</span><span style="color: #000000;"> Rule10022(IOptionValueProvider options)
{
</span><span style="color: #008000;">//</span><span style="color: #008000;"> "CA_PACKSHAPE eq 'B' and NOT ('2755900-0100' IN CA_REBUILDING_KIT)"</span><span style="color: #008000;">
</span><span style="color: #000000;">
</span><span style="color: #0000FF;">return</span><span style="color: #000000;"> (String.Compare(options.GetOptionValueAsString(</span><span style="color: #800080;">1009</span><span style="color: #000000;">), </span><span style="color: #800000;">"</span><span style="color: #800000;">B</span><span style="color: #800000;">"</span><span style="color: #000000;">, StringComparison.OrdinalIgnoreCase) </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">) </span><span style="color: #000000;">&&</span><span style="color: #000000;"> (</span><span style="color: #000000;">!</span><span style="color: #000000;">(options.CheckValueInOption(</span><span style="color: #800000;">"</span><span style="color: #800000;">2755900-0100</span><span style="color: #800000;">"</span><span style="color: #000000;">, </span><span style="color: #800080;">1495</span><span style="color: #000000;">, OptionDataType.String)));
}</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>
<p><strong><u>IL Code</u></strong></p>
<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"><pre style="background-color:#FFFFFF;overflow: auto;;font-family:Consolas;font-size:12"><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">static</span><span style="color: #000000;"> </span><span style="color: #0000FF;">void</span><span style="color: #000000;"> Rule10022CIL(TypeGen typeGen)
{
CodeGen g </span><span style="color: #000000;">=</span><span style="color: #000000;"> typeGen.Public.Static.Method(</span><span style="color: #0000FF;">typeof</span><span style="color: #000000;"> (</span><span style="color: #0000FF;">bool</span><span style="color: #000000;">), </span><span style="color: #800000;">"</span><span style="color: #800000;">Rule10022</span><span style="color: #800000;">"</span><span style="color: #000000;">).Parameter(</span><span style="color: #0000FF;">typeof</span><span style="color: #000000;"> (IOptionValueProvider), </span><span style="color: #800000;">"</span><span style="color: #800000;">options</span><span style="color: #800000;">"</span><span style="color: #000000;">);
{
Operand op1 </span><span style="color: #000000;">=</span><span style="color: #000000;"> Static.Invoke(</span><span style="color: #0000FF;">typeof</span><span style="color: #000000;"> (String), </span><span style="color: #800000;">"</span><span style="color: #800000;">Compare</span><span style="color: #800000;">"</span><span style="color: #000000;">, g.Arg(</span><span style="color: #800000;">"</span><span style="color: #800000;">options</span><span style="color: #800000;">"</span><span style="color: #000000;">).Invoke(</span><span style="color: #800000;">"</span><span style="color: #800000;">GetOptionValueAsString</span><span style="color: #800000;">"</span><span style="color: #000000;">, </span><span style="color: #800080;">1009</span><span style="color: #000000;">), </span><span style="color: #800000;">"</span><span style="color: #800000;">B</span><span style="color: #800000;">"</span><span style="color: #000000;">, StringComparison.OrdinalIgnoreCase) </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">;
Operand op2 </span><span style="color: #000000;">=</span><span style="color: #000000;"> g.Arg(</span><span style="color: #800000;">"</span><span style="color: #800000;">options</span><span style="color: #800000;">"</span><span style="color: #000000;">).Invoke(</span><span style="color: #800000;">"</span><span style="color: #800000;">CheckValueInOption</span><span style="color: #800000;">"</span><span style="color: #000000;">, </span><span style="color: #800000;">"</span><span style="color: #800000;">2755900-0100</span><span style="color: #800000;">"</span><span style="color: #000000;">, </span><span style="color: #800080;">1495</span><span style="color: #000000;">, OptionDataType.String);
g.Return((op1) </span><span style="color: #000000;">&&</span><span style="color: #000000;"> (</span><span style="color: #000000;">!</span><span style="color: #000000;">op2));
}
}</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>
<p>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.  The one or two issues that we discovered were quickly corrected by the author of the library <a href="http://code.google.com/u/@VhhXR1BYDhhEVgJ%2B/">Stefan Simek</a>.  So if you ever want to create IL code at run-time again, you should really seriously consider RunSharp.  As the post title says, it really is IL generation for Dummies.</p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com0tag:blogger.com,1999:blog-4775121157402872976.post-74012621424841019832010-06-01T12:35:00.001+02:002010-06-01T12:35:37.079+02:00C# Coding Standards Using ReSharper<p>I found the following <a href="http://gojisoft.com/blog/2010/05/10/coding-standards-using-resharper/">great blog post</a> by Tim Lloyd on how to setup coding standards for your development environment using <a href="http://www.jetbrains.com/resharper/">ReSharper 5.0</a>.  We’ve done pretty much the same thing in our environment although I wasn’t aware of the <a href="http://rsm.codeplex.com/">ReSharper Settings Manager</a> which I will test drive soon as I have found sharing settings between team members to be a real pain.  Seems like JetBrains will look at this for v6 though.  Things we are doing in addition to the content mentioned by Tim are:</p> <ol> <li>Using Agent Smith to ensure the correctness of the spelling for our resource files etc. </li> <li>Created a more advanced layout template to order all our code using the same structure when doing <a href="http://www.jetbrains.com/resharper/features/code_formatting.html">Code Cleanup</a> </li> </ol> <p>It works great if everybody in the team follows the agreed upon procedure.  I find that this makes code reviews focus on the right things – the actual business logic!</p> Carel Lotzhttp://www.blogger.com/profile/13701537592037249529noreply@blogger.com0