<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Random Musings of Jeremy Jameson : Core Development</title><link>http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx</link><description>Tags: Core Development</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>The "Copy Local" Bug in Visual Studio</title><link>http://blogs.msdn.com/jjameson/archive/2009/11/18/the-copy-local-bug-in-visual-studio.aspx</link><pubDate>Wed, 18 Nov 2009 12:21:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9924246</guid><dc:creator>Jeremy Jameson</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/jjameson/comments/9924246.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jjameson/commentrss.aspx?PostID=9924246</wfw:commentRss><description>&lt;P&gt;If you've ever worked with me on a Microsoft Office SharePoint Server (MOSS) 2007 project -- or if you've read my &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/09/28/sample-walkthrough-of-the-dr-dada-approach-to-sharepoint.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/09/28/sample-walkthrough-of-the-dr-dada-approach-to-sharepoint.aspx"&gt;Sample Walkthrough of the DR.DADA Approach to SharePoint&lt;/A&gt; -- then you've probably seen the following comment:&lt;/P&gt;
&lt;BLOCKQUOTE class=directQuote&gt;
&lt;P&gt;Note: Referenced assemblies must be specified with a path corresponding to the build configuration. If the path is not specified to the referenced assembly, then the build works fine as long as the referenced assembly is not in the GAC.&lt;/P&gt;
&lt;P&gt;However, when the referenced assembly is in the GAC (i.e. after a deployment) then MakeCAB will not be able to find the referenced assembly (since it is no longer copied to the current project's bin\Debug or bin\Release folder).&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;It turns out that I was using a rather elaborate workaround for a problem that is actually much easier to solve.&lt;/P&gt;
&lt;P&gt;To workaround the "Copy Local" bug and force a referenced assembly to always be copied to the output folder (regardless of whether the referenced assembly is in the GAC):&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;In the &lt;STRONG&gt;Solution Explorer &lt;/STRONG&gt;window in Visual Studio, expand the &lt;STRONG&gt;References&lt;/STRONG&gt; folder for the project and then select the referenced assembly.&lt;/LI&gt;
&lt;LI&gt;In the &lt;STRONG&gt;Properties &lt;/STRONG&gt;window, change the value of &lt;STRONG&gt;Copy Local &lt;/STRONG&gt;to &lt;STRONG&gt;False&lt;/STRONG&gt;, and then change it back to &lt;STRONG&gt;True&lt;/STRONG&gt;.&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Following these two simple steps explicitly adds &lt;CODE&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Private&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;True&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Private&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/CODE&gt; to the project file, as shown in the following example:&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;PRE&gt;&lt;CODE&gt;    &lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;ProjectReference&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;Include&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;..\CoreServices\CoreServices.csproj&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Project&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;{01C58D27-9818-45D6-A0B6-8EF765CA9397}&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Project&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;CoreServices %28CoreServices\CoreServices%29&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Private&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;True&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;Private&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;ProjectReference&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/CODE&gt;&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;When you add a referenced assembly in Visual Studio using a project reference, &lt;STRONG&gt;Copy Local &lt;/STRONG&gt;defaults to &lt;STRONG&gt;True&lt;/STRONG&gt;, but Visual Studio doesn't explicitly state this in the MSBuild project file. Toggling the value of &lt;STRONG&gt;Copy Local &lt;/STRONG&gt;forces this element to be added to the project file and consequently you no longer need any hacks to reference the assembly in its original output folder.&lt;/P&gt;
&lt;P&gt;At this point, you might be wondering why do I bring this up after all this time? After all, hasn't the hack I came up with for building SharePoint Web Solution Packages (WSPs) been working for several years? Well, yes, in most cases it works just fine.&lt;/P&gt;
&lt;P&gt;However, there's one fundamental problem that I only recently discovered back in early October: you can't use Team Foundation Build to build the WSP when specifying relative paths to assemblies in the DDF file.&lt;/P&gt;
&lt;P&gt;I'll cover this in &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/11/18/building-sharepoint-wsps-with-team-foundation-build.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/11/18/building-sharepoint-wsps-with-team-foundation-build.aspx"&gt;my next post&lt;/A&gt;.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9924246" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jjameson/archive/tags/MOSS+2007/default.aspx">MOSS 2007</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx">Core Development</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/WSS+v3/default.aspx">WSS v3</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Visual+Studio/default.aspx">Visual Studio</category></item><item><title>SketchPath - The XPath Tool</title><link>http://blogs.msdn.com/jjameson/archive/2009/11/18/sketchpath-the-xpath-tool.aspx</link><pubDate>Wed, 18 Nov 2009 11:40:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9924233</guid><dc:creator>Jeremy Jameson</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/jjameson/comments/9924233.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jjameson/commentrss.aspx?PostID=9924233</wfw:commentRss><description>&lt;P&gt;I added another tool to my &lt;A href="http://blogs.msdn.com/jjameson/archive/2007/03/22/backedup-and-notbackedup.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2007/03/22/backedup-and-notbackedup.aspx"&gt;Toolbox&lt;/A&gt; yesterday: SketchPath.&lt;/P&gt;
&lt;P&gt;The &lt;A href="http://www.sketchpath.com/" mce_href="http://www.sketchpath.com"&gt;SketchPath site&lt;/A&gt; labels it as "The XPath Tool" but I'd say it more like "&lt;EM&gt;The&lt;/EM&gt; XPath Tool."&lt;/P&gt;
&lt;P&gt;I've seen a few other tools for quickly building and testing XPath expressions against an XML document, but they pale in comparison to SketchPath. There are a number of online tools that unquestionably require less effort to get started with, but you'll likely find them very limiting as well.&lt;/P&gt;
&lt;P&gt;I know I'm not the only one who thinks SketchPath rocks. Scott Hanselman included it in his &lt;A href="http://www.hanselman.com/blog/ScottHanselmans2009UltimateDeveloperAndPowerUsersToolListForWindows.aspx" mce_href="http://www.hanselman.com/blog/ScottHanselmans2009UltimateDeveloperAndPowerUsersToolListForWindows.aspx"&gt;2009 Ultimate Developer and Power Users Tool List for Windows&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;If you do any significant amount of work with XML, I recommend you download SketchPath today.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9924233" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx">Core Development</category></item><item><title>Compiling C++ Projects with Team Foundation Build</title><link>http://blogs.msdn.com/jjameson/archive/2009/11/07/compiling-c-projects-with-team-foundation-build.aspx</link><pubDate>Sat, 07 Nov 2009 16:24:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9919079</guid><dc:creator>Jeremy Jameson</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/jjameson/comments/9919079.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jjameson/commentrss.aspx?PostID=9919079</wfw:commentRss><description>&lt;P&gt;As I mentioned in my &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/11/07/using-password-minder-to-manage-your-passwords.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/11/07/using-password-minder-to-manage-your-passwords.aspx"&gt;previous post&lt;/A&gt;, this week I incorporated Password Minder into my "Toolbox" Visual Studio solution that is scheduled to build daily through Team Foundation Server (TFS).&lt;/P&gt;
&lt;P&gt;It's not that I really need daily builds of Password Minder; rather it's just been something on my "TO DO" list for a long time and I finally got around to doing it. Unfortunately, it wasn't without issue.&lt;/P&gt;
&lt;P&gt;In case you are not familiar with Password Minder, it is mostly written in C#, but it includes one C++ project (for the NativeHelpers.dll).&lt;/P&gt;
&lt;P&gt;Thus when I added the Password Minder projects to my "Toolbox" solution, I woke up the next morning to a notification from Team Foundation Server that my build failed. [No, I don't have some sort of alarm that goes off when one of my builds break. By "notification" I am referring to the e-mail message that I found in my inbox when I sat down at the computer.]&lt;/P&gt;
&lt;P&gt;Clicking the build log referenced in the e-mail message, I quickly discovered the following:&lt;/P&gt;
&lt;DIV class=logExcerpt&gt;&lt;SAMP&gt;Using "VCBuild" task from assembly "Microsoft.Build.Tasks.v3.5, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". Task "VCBuild"&lt;BR&gt;Locating vcbuild.exe: not found at "c:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\..\..\vc\vcpackages\vcbuild.exe".&lt;BR&gt;Locating vcbuild.exe: Visual C++ Express is not installed on this computer.&lt;BR&gt;Locating vcbuild.exe: falling back to the system PATH variable.&lt;BR&gt;C:\Users\svc-build\AppData\Local\Temp\Toolbox\Automated Build - Main\Sources\Source\Toolbox.sln : error MSB3411: Could not load the Visual C++ component "VCBuild.exe". If the component is not installed, either 1) install the Microsoft Windows SDK for Windows Server 2008 and .NET Framework 3.5, or 2) install Microsoft Visual Studio 2008.&lt;/SAMP&gt;&lt;/DIV&gt;
&lt;P&gt;That certainly is one of the best error messages I've seen in a long time. It told me exactly what I needed to do to fix the problem. Well, almost...&lt;/P&gt;
&lt;P&gt;Note that DAZZLER (a VM in the &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/09/14/the-jameson-datacenter.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/09/14/the-jameson-datacenter.aspx"&gt;"Jameson Datacenter"&lt;/A&gt; that is my dedicated build server) does not have the full installation of Visual Studio 2008. Rather it only has the Team Foundation Build install. In keeping with best practices, I try to keep the build server as "clean" as possible. That means no Visual Studio, no SharePoint, etc.&lt;/P&gt;
&lt;P&gt;Following option #1 from the log file, I proceeded to install the Microsoft Windows SDK for Windows Server 2008 and .NET Framework 3.5 -- but, of course, I didn't bother to review the ReadMe file that comes with it (at least not at first).&lt;/P&gt;
&lt;P&gt;Consequently, I was greeted with the following error on the next build attempt:&lt;/P&gt;
&lt;DIV class=logExcerpt&gt;&lt;SAMP&gt;c:\Windows\Microsoft.NET\Framework\v3.5\Microsoft.Common.targets : warning MSB3428: Could not load the Visual C++ component "VCProjectEngine.dll". To fix this, 1) install the Microsoft Windows SDK for Windows Server 2008 and .NET Framework 3.5, 2) install Microsoft Visual Studio 2008 or 3) add the location of the component to the system path if it is installed elsewhere. System error code: 126.&lt;BR&gt;c:\Windows\Microsoft.NET\Framework\v3.5\Microsoft.Common.targets : warning MSB3425: Could not resolve VC project reference "..\NativeHelpers\NativeHelpers.vcproj".&lt;/SAMP&gt;&lt;/DIV&gt;
&lt;P&gt;That's when I discovered the following from the release notes for the SDK:&lt;/P&gt;
&lt;BLOCKQUOTE class=directQuote&gt;
&lt;H4&gt;5.1.1 VCBuild fails to compile or upgrade projects&lt;/H4&gt;
&lt;P&gt;In order for VCBuild to run properly, vcprojectengine.dll needs to be registered. If vcprojectengine.dll is not registered, VCBuild.exe will fail with errors such as:&lt;/P&gt;
&lt;P&gt;On compile: &lt;CODE&gt;warning MSB3422: Failed to retrieve VC project information through the VC project engine object model. System error code: 127.&lt;/CODE&gt;&lt;/P&gt;
&lt;P&gt;On upgrade: &lt;CODE&gt;Failed to upgrade project file ‘foo.vcproj'. Please make sure the file exists and is not write-protected.&lt;/CODE&gt;&lt;/P&gt;
&lt;P&gt;To workaround this issue, &lt;CODE&gt;vcprojectengine.dll&lt;/CODE&gt; must be manually registered. From a Windows SDK command line window (as administrator in Vista:&lt;/P&gt;
&lt;P&gt;On an X86 machine, run:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;cd %mssdk%\VC\bin
regsvr32 vcprojectengine.dll&lt;/CODE&gt;&lt;/PRE&gt;
&lt;P&gt;On an X64 machine, run:&lt;/P&gt;&lt;PRE&gt;&lt;CODE&gt;cd %mssdk%\VC\bin\X64
regsvr32 vcprojectengine.dll&lt;/CODE&gt;&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Unfortunately, these instructions aren't quite right -- or at least they didn't work verbatim in my environment. The workaround stated above makes you think there's an environment variable (&lt;CODE&gt;%mssdk%&lt;/CODE&gt;) that refers to the path where the SDK is installed. However, this wasn't configured on DAZZLER.&lt;/P&gt;
&lt;P&gt;Also, I didn't find my copy of VCProjectEngine.dll in an &lt;STRONG&gt;x64 &lt;/STRONG&gt;folder, but rather in an &lt;STRONG&gt;amd64 &lt;/STRONG&gt;folder:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\amd64\VCProjectEngine.dll&lt;/BLOCKQUOTE&gt;
&lt;P&gt;I know most of you out there are not doing much (if any) C++ work anymore, but I thought I should share this just in case you need it at some point.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9919079" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx">Core Development</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/TFS/default.aspx">TFS</category></item><item><title>Recommendations for Code Analysis</title><link>http://blogs.msdn.com/jjameson/archive/2009/10/31/recommendations-for-code-analysis.aspx</link><pubDate>Sat, 31 Oct 2009 13:44:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9915654</guid><dc:creator>Jeremy Jameson</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/jjameson/comments/9915654.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jjameson/commentrss.aspx?PostID=9915654</wfw:commentRss><description>&lt;P&gt;In my &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/10/31/recommended-check-in-policies-for-team-foundation-server.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/10/31/recommended-check-in-policies-for-team-foundation-server.aspx"&gt;previous post&lt;/A&gt;, I briefly mentioned the Code Analysis feature of Visual Studio in the context of using check-in policies with Team Foundation Server (TFS). However, there's a lot more to talk about with regards to using Code Analysis.&lt;/P&gt;
&lt;P&gt;If you are ever find yourself "starting from a clean slate" on a software development project, I hope you take advantage of the opportunity to not only enable Code Analysis, but also to treat all Code Analysis warnings as errors. That's right, go ahead and check all of those boxes (for both &lt;STRONG&gt;Debug &lt;/STRONG&gt;and &lt;STRONG&gt;Release &lt;/STRONG&gt;configurations, of course) so that whenever potential issues are reported by Code Analysis, it stops developers dead in their tracks and considers the build to be broken.&lt;/P&gt;
&lt;P&gt;While you're at it, go ahead and select the &lt;STRONG&gt;All &lt;/STRONG&gt;option in the &lt;STRONG&gt;Treat warnings as errors &lt;/STRONG&gt;section on the &lt;STRONG&gt;Build &lt;/STRONG&gt;tab (something I definitely recommend as a best practice). Again, be sure to do this for all build configurations.&lt;/P&gt;
&lt;P&gt;Yes, this is going to be really painful for some developers.&lt;/P&gt;
&lt;P&gt;For example, you can say goodbye to using the overload of string.Format() that doesn't specify a CultureInfo:&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;PRE&gt;&lt;CODE&gt;            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; foo = &lt;SPAN style="COLOR: #a31515"&gt;"here"&lt;/SPAN&gt;;

            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; logMessage = &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.Format(
                &lt;SPAN style="COLOR: #a31515"&gt;"Imagine something interesting {0}."&lt;/SPAN&gt;,
                foo);&lt;/CODE&gt;&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;Attempting this will now result in a broken build:&lt;/P&gt;
&lt;BLOCKQUOTE class="directQuote errorMessage"&gt;Error 2 CA1305 : Microsoft.Globalization : Because the behavior of 'string.Format(string, object)' could vary based on the current user's locale settings, replace this call in 'Program.Main(string[])' with a call to 'string.Format(IFormatProvider, string, params object[])'. If the result of 'string.Format(IFormatProvider, string, params object[])' will be displayed to the user, specify 'CultureInfo.CurrentCulture' as the 'IFormatProvider' parameter. Otherwise, if the result will be stored and accessed by software, such as when it is persisted to disk or to a database, specify 'CultureInfo.InvariantCulture'. &lt;/BLOCKQUOTE&gt;
&lt;P&gt;To avoid the CA1305 error, you will need to use something like this instead:&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;PRE&gt;&lt;CODE&gt;            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; foo = &lt;SPAN style="COLOR: #a31515"&gt;"here"&lt;/SPAN&gt;;

            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; logMessage = &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.Format(
                &lt;SPAN style="COLOR: #2b91af"&gt;CultureInfo&lt;/SPAN&gt;.InvariantCulture,
                &lt;SPAN style="COLOR: #a31515"&gt;"Imagine something interesting {0}."&lt;/SPAN&gt;,
                foo);&lt;/CODE&gt;&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;You will also need to enable signing of all assemblies with a strong name key, and also specify various assembly level attributes (e.g. &lt;A href="http://msdn.microsoft.com/en-us/library/system.clscompliantattribute.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.clscompliantattribute.aspx"&gt;&lt;CODE&gt;[assembly: CLSCompliant(true)]&lt;/CODE&gt;&lt;/A&gt;). However, if you follow the steps I've provided in a &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/04/03/shared-assembly-info-in-visual-studio-projects.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/04/03/shared-assembly-info-in-visual-studio-projects.aspx"&gt;previous post&lt;/A&gt;, this should only take you at most 1-2 minutes.&lt;/P&gt;
&lt;P&gt;Like I said before, this will probably cause some heartburn in the beginning, but trust me, developers will quickly get used to it and the code they write will be much better as a result.&lt;/P&gt;
&lt;P&gt;Now what about the other 99% of the time when you aren't starting from a clean slate, but instead are dealing with a substantial code base that causes the Code Analysis feature in Visual Studio to "light up like a Christmas tree" when you turn it on?&lt;/P&gt;
&lt;P&gt;Well, as with all software bugs, it all comes down to &lt;EM&gt;triage&lt;/EM&gt;. You obviously cannot simply halt all feature development in order to resolve code analysis issues. Instead, you should go for the "low hanging fruit" (meaning the issues that occur frequently but can be resolved with relatively little effort or risk of changing). You should also try to enable the Code Analysis rules that are most important, such as potential security issues.&lt;/P&gt;
&lt;P&gt;The following post provides some great information about which Code Analysis warnings to focus your attention on first:&lt;/P&gt;
&lt;DIV class=reference&gt;&lt;CITE&gt;What rules do Microsoft have turned on internally? 2007-08-09.&lt;/CITE&gt; 
&lt;DIV class=referenceLink&gt;&lt;A href="http://blogs.msdn.com/fxcop/archive/2007/08/09/what-rules-do-microsoft-have-turned-on-internally.aspx" mce_href="http://blogs.msdn.com/fxcop/archive/2007/08/09/what-rules-do-microsoft-have-turned-on-internally.aspx"&gt;http://blogs.msdn.com/fxcop/archive/2007/08/09/what-rules-do-microsoft-have-turned-on-internally.aspx&lt;/A&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;This article is obviously a little dated, but still very relevant over two years later.&lt;/P&gt;
&lt;P&gt;Note that you will undoubtedly need to &lt;A href="http://msdn.microsoft.com/en-us/library/ms244717.aspx" mce_href="http://msdn.microsoft.com/en-us/library/ms244717.aspx"&gt;suppress some specific Code Analysis warnings&lt;/A&gt; from time to time, and therefore you'll have to choose how to suppress the warnings (whether inline within the source, or in a GlobalSuppressions.cs file). However, I hope you'll choose to fix the underlying issue that causes the Code Analysis warning (whenever practical) instead of simply suppressing a bunch of warnings.&lt;/P&gt;
&lt;P&gt;So, in conclusion, think of the Code Analysis feature in Visual Studio as a way of &lt;EM&gt;choosing&lt;/EM&gt; a more strict compiler. For example, back in the days when I used to program in C on Unix, the compiler wouldn't complain when I wrote something like this (even though this is obviously very wrong):&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;PRE&gt;&lt;CODE&gt;            &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (i = 1)
            {
                ...
            }&lt;/CODE&gt;&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;I was relieved when I switched to C++ and these kinds of bugs were a thing of the past. [Note that I never switch my coding style to use something like "&lt;CODE&gt;1 == i&lt;/CODE&gt;" in order to avoid these errors.]&lt;/P&gt;
&lt;P&gt;Fortunately, in C# you don't have a choice about whether or not this compiles (it doesn't).&lt;/P&gt;
&lt;P&gt;I like to think of enabling all of the Code Analysis rules in a similar fashion. In other words, I want the compiler to tell me whenever I am doing something potentially wrong, because then I can spend just a little bit of time fixing my code to do it right. By forcing the Code Analysis warnings as errors, I don't have a choice -- meaning I have to fix them before check-in.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9915654" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jjameson/archive/tags/My+System/default.aspx">My System</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx">Core Development</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Visual+Studio/default.aspx">Visual Studio</category></item><item><title>Recommended Check-In Policies for Team Foundation Server</title><link>http://blogs.msdn.com/jjameson/archive/2009/10/31/recommended-check-in-policies-for-team-foundation-server.aspx</link><pubDate>Sat, 31 Oct 2009 12:14:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9915639</guid><dc:creator>Jeremy Jameson</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/jjameson/comments/9915639.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jjameson/commentrss.aspx?PostID=9915639</wfw:commentRss><description>&lt;P&gt;I love using Team Foundation Server (TFS). There's just an amazing amount of "goodness" for software development that comes out-of-the-box; and there's even more available from Microsoft and other sources in the form of add-ons (many of which are free).&lt;/P&gt;
&lt;P&gt;From a source control perspective, one of my favorite features is check-in policies. Anything that improves the quality of software development with minimal effort is really a "&lt;A href="http://wordnetweb.princeton.edu/perl/webwn?s=no-brainer" mce_href="http://wordnetweb.princeton.edu/perl/webwn?s=no-brainer"&gt;no-brainer&lt;/A&gt;" in my opinion.&lt;/P&gt;
&lt;P&gt;The check-in policies that I prefer to have configured on all TFS projects are listed in the following table.&lt;/P&gt;
&lt;TABLE class=accent1 cellSpacing=0 class="accent1"&gt;
&lt;CAPTION&gt;Recommended TFS Check-In Policies&lt;/CAPTION&gt;
&lt;THEAD&gt;
&lt;TR&gt;
&lt;TH&gt;Policy Type&lt;/TH&gt;
&lt;TH&gt;Description&lt;/TH&gt;&lt;/TR&gt;&lt;/THEAD&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;Builds&lt;/TD&gt;
&lt;TD&gt;This policy requires that any code changes have been compiled and the last build was successful.&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;Work Items&lt;/TD&gt;
&lt;TD&gt;This policy requires that one or more work items be associated with every check-in.&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;Changeset Comments Policy&lt;/TD&gt;
&lt;TD&gt;Reminds users to add meaningful comments to their check-ins.&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;Code Analysis&lt;/TD&gt;
&lt;TD&gt;This policy requires that Code Analysis is run with a defined set of rules before check-in.&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;Testing Policy&lt;/TD&gt;
&lt;TD&gt;Ensures that tests from specific test lists are successfully executed before checking in.&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;The first two check-in policies are virtually painless and can be applied to any existing project at any time. These policies ship with Visual Studio Team System 2008, and assuming your developers have good software development discipline already, there's absolutely no reason not to enable these policies.&lt;/P&gt;
&lt;P&gt;After all, why would any developer want to check-in code that hasn't been verified to at least compile? Similarly, why would a developer make a code change that isn't specifically related to a work item (even if that work item is simply something like "Refactor X" or "Code cleanup (M5)")?&lt;/P&gt;
&lt;P&gt;However, the last three policies in the table above require a little more effort.&lt;/P&gt;
&lt;P&gt;The Changeset Comments Policy is included in the &lt;A href="http://msdn.microsoft.com/en-us/teamsystem/bb980963.aspx" mce_href="http://msdn.microsoft.com/en-us/teamsystem/bb980963.aspx"&gt;Team Foundation Server Power Tools&lt;/A&gt;, which means that every member of the Development team will need to download and install this in order to use it. (Note that if you don't have the Power Tools installed, you can still override the check-in policy in order to avoid being blocked.)&lt;/P&gt;
&lt;P&gt;The Code Analysis policy can definitely cause a little heartburn for your Development team, depending on how many code analysis rules you enable and whether or not you treat these warnings as errors. I'll talk more about Code Analysis in a separate post.&lt;/P&gt;
&lt;P&gt;The Testing Policy is not one that I consider essential for all projects. For projects in which you have a good set of Build Verification Tests (BVTs) that give you a signficant amount of code coverage and don't take very long to execute, then enabling this policy just makes sense. However, keep in mind that you should definitely be running BVTs as part of your automated build, so if these tests require a substantial amount of time to execute (for example, they require signficant setup or teardown), then forcing developers to run these tests before every check-in could definitely impede their productivity.&lt;/P&gt;
&lt;P&gt;Of course, you can always separate your tests into "quick tests" and "long running tests" like I've mentioned in a previous &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/03/19/argumentnullexception-with-optional-publishingpage-description-property-with-some-thoughts-on-breaking-the-build-too.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/03/19/argumentnullexception-with-optional-publishingpage-description-property-with-some-thoughts-on-breaking-the-build-too.aspx"&gt;post&lt;/A&gt;, and consequently only require the "quick tests" to be executed before check-in.&lt;/P&gt;
&lt;P&gt;If you are fortunate enough to be using TFS on your project, I hope you are reaping the benefits of check-in policies.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9915639" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jjameson/archive/tags/My+System/default.aspx">My System</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx">Core Development</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/TFS/default.aspx">TFS</category></item><item><title>Build and Deployment Overview</title><link>http://blogs.msdn.com/jjameson/archive/2009/09/26/build-and-deployment-overview.aspx</link><pubDate>Sat, 26 Sep 2009 19:40:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9899878</guid><dc:creator>Jeremy Jameson</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/jjameson/comments/9899878.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jjameson/commentrss.aspx?PostID=9899878</wfw:commentRss><description>&lt;P&gt;This post provides a high-level walkthrough of the build and deployment process that I typically recommend on projects that I am involved with. It includes a series of illustrations that capture key concepts at various points in time. Specific parts of the process -- such as the &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/09/25/development-and-build-environments.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/09/25/development-and-build-environments.aspx"&gt;development and build environments&lt;/A&gt;, &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/04/03/best-practices-for-net-assembly-versioning.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/04/03/best-practices-for-net-assembly-versioning.aspx"&gt;versioning&lt;/A&gt;, and &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/09/26/best-practices-for-scm-and-the-daily-build-process.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/09/26/best-practices-for-scm-and-the-daily-build-process.aspx"&gt;source control&lt;/A&gt; -- have already been covered in previous posts.&lt;/P&gt;
&lt;P&gt;The following figure illustrates the initial build and deployment of the solution.&lt;/P&gt;
&lt;DIV class=image&gt;&lt;IMG title="" alt="" src="http://blogs.msdn.com/photos/jjameson/images/9899439/500x216.aspx" width=500 height=216 mce_src="http://blogs.msdn.com/photos/jjameson/images/9899439/500x216.aspx"&gt; 
&lt;DIV class=caption&gt;Figure 1: Initial build and deployment of the solution&lt;/DIV&gt;
&lt;DIV class=imageLink&gt;&lt;A href="http://blogs.msdn.com/photos/jjameson/images/9899439/original.aspx" target=_blank mce_href="http://blogs.msdn.com/photos/jjameson/images/9899439/original.aspx"&gt;See full-sized image.&lt;/A&gt; &lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;Note the following key steps (corresponding to the various arrows in Figure 1):&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Using their local environments, members of the Development team add new code – or modify existing code – and subsequently check the code into the source control system.&lt;/LI&gt;
&lt;LI&gt;On the Build Server, the entire solution is labeled in the source control system to “snapshot” the exact state of the solution at the point in time just prior to the build. The label includes the version number (for example, &lt;STRONG&gt;1.0.1.0 &lt;/STRONG&gt;in the case of the initial build).&lt;/LI&gt;
&lt;LI&gt;Using the label established in the previous step, all of the source code for the solution is copied from the Source Control Server to the Build Server, thereby ensuring that what is compiled into a specific version of the solution is based on the corresponding version of the source code in the source control system.&lt;/LI&gt;
&lt;LI&gt;The solution is then compiled on the Build Server.&lt;/LI&gt;
&lt;LI&gt;Next, the output of the build is copied from the Build Server to the Release Server (in a subfolder on the Builds share). The location of the build output on the Release Server includes the build number (e.g. 1.0.1.0) as well as the build configuration such as Debug or Release (note that the build configuration is not illustrated in Figure 1). The initial build often contains nothing more than the compiled code, which may be a group of assemblies (i.e. a number of EXE and/or DLL files) or a setup package (i.e. an MSI or CAB file) but most likely does not have an installation guide or installation scripts.&lt;/LI&gt;
&lt;LI&gt;The solution is then installed by the Development team into the Development Integration Environment (DEV). This initial installation is typically performed manually (for example, by copying files, registering assemblies, modifying the server configuration, and/or interactively stepping through a setup program).&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;Figure 2 shows a subsequent build of the solution.&lt;/P&gt;
&lt;DIV class=image&gt;&lt;IMG title="" alt="" src="http://blogs.msdn.com/photos/jjameson/images/9899440/500x234.aspx" width=500 height=234 mce_src="http://blogs.msdn.com/photos/jjameson/images/9899440/500x234.aspx"&gt; 
&lt;DIV class=caption&gt;Figure 2: Subsequent build and deployment (with draft of installation guide)&lt;/DIV&gt;
&lt;DIV class=imageLink&gt;&lt;A href="http://blogs.msdn.com/photos/jjameson/images/9899440/original.aspx" target=_blank mce_href="http://blogs.msdn.com/photos/jjameson/images/9899440/original.aspx"&gt;See full-sized image.&lt;/A&gt; &lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;The steps performed in the initial build (illustrated in Figure 1) are repeated in this subsequent build. The key difference illustrated in Figure 2 is the inclusion of the installation guide (which documents the manual steps performed by the Development team during the initial deployment). The new build (in this example, &lt;STRONG&gt;1.0.2.0&lt;/STRONG&gt;) is then deployed to the DEV environment by following the installation guide.&lt;/P&gt;
&lt;P&gt;While this deployment process is functional -- in that a new build of the solution is successfully deployed to the DEV environment -- it requires too much manual effort to sustain the process. Figure 3 shows yet another subsequent build in which the manual installation to DEV has been replaced by an automated process.&lt;/P&gt;
&lt;DIV class=image&gt;&lt;IMG title="" alt="" src="http://blogs.msdn.com/photos/jjameson/images/9899441/500x293.aspx" width=500 height=293 mce_src="http://blogs.msdn.com/photos/jjameson/images/9899441/500x293.aspx"&gt; 
&lt;DIV class=caption&gt;Figure 3: Automated build and deployment (with install scripts and updated installation guide)&lt;/DIV&gt;
&lt;DIV class=imageLink&gt;&lt;A href="http://blogs.msdn.com/photos/jjameson/images/9899441/original.aspx" target=_blank mce_href="http://blogs.msdn.com/photos/jjameson/images/9899441/original.aspx"&gt;See full-sized image.&lt;/A&gt; &lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;Note that in Figure 3, the automated installation process actually installs version 1.0.3.0 but installs it from the Latest folder on the Release Server. At the point in time represented in Figure 3, the contents of the &lt;STRONG&gt;Latest&lt;/STRONG&gt; and &lt;STRONG&gt;1.0.3.0 &lt;/STRONG&gt;folders are identical. Using this mirrored structure greatly simplifies the automated installs of the latest build into the DEV environment. Also note that the build illustrated in Figure 3 includes install scripts, in addition to the build output (i.e. compiled code) and the installation guide (which has been updated to specify the install scripts to be used for installing the solution). These install scripts are a key piece of the automated installation process -- and subsequent “manual” installs into other environments (as described below).&lt;/P&gt;
&lt;P&gt;Note that the process illustrated in Figure 3 does not require any manual intervention and can therefore be performed on a scheduled basis (à la, the “daily build”) or ad hoc, simply by executing the scheduled task as desired. Each subsequent build includes the source code changes checked-in to the source control system -- thus incorporating new features and bug fixes -- and is automatically installed into the DEV environment -- thus providing visibility to all team members on the progress of development. This is particularly useful for the Test team (in order to create test cases).&lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Note&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;The daily build provides a “heartbeat” of the development effort that can be monitored regularly by all team members – not just the Development team.&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;As this cycle repeats (as more features are implemented in the solution), the Test team – in conjunction with the Development team -- identifies a specific build of the solution to promote to the TEST environment. This is illustrated in Figure 4.&lt;/P&gt;
&lt;DIV class=image&gt;&lt;IMG title="" alt="" src="http://blogs.msdn.com/photos/jjameson/images/9899442/500x293.aspx" width=500 height=293 mce_src="http://blogs.msdn.com/photos/jjameson/images/9899442/500x293.aspx"&gt; 
&lt;DIV class=caption&gt;Figure 4: Installing the Beta 1 version to TEST&lt;/DIV&gt;
&lt;DIV class=imageLink&gt;&lt;A href="http://blogs.msdn.com/photos/jjameson/images/9899442/original.aspx" target=_blank mce_href="http://blogs.msdn.com/photos/jjameson/images/9899442/original.aspx"&gt;See full-sized image.&lt;/A&gt; &lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;Note the following key concepts illustrated in the previous figure:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;The build selected by the Test team does not necessarily correspond to the latest build -- as indicated by the ellipsis (…) after &lt;STRONG&gt;1.0.57.0&lt;/STRONG&gt; in Figure 4. It is common for a later build of the solution to be running in the DEV environment, as a result of the daily build.&lt;/LI&gt;
&lt;LI&gt;At one point in time, the version of the solution selected by the Test team was automatically installed to the DEV environment – as indicated by the dashed line in the previous figure.&lt;/LI&gt;
&lt;LI&gt;Before installing the selected build to the TEST environment, the corresponding label in the source control system is annotated – as indicated by &lt;STRONG&gt;(Beta 1)&lt;/STRONG&gt; in Figure 4. This allows the Development team to quickly get the version of the source code in order to debug problems encountered in the TEST environment.&lt;/LI&gt;
&lt;LI&gt;The Test team installs the solution in the TEST environment by following the installation guide (which details the install scripts and configuration steps to be used).&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Just as the daily build process (illustrated in Figure 3) is repeated throughout the development process, the promotion of selected builds to TEST is also periodically repeated, albeit much less frequently. This is illustrated in Figure 5 with the first “release candidate” of the solution.&lt;/P&gt;
&lt;DIV class=image&gt;&lt;IMG title="" alt="" src="http://blogs.msdn.com/photos/jjameson/images/9899443/500x293.aspx" width=500 height=293 mce_src="http://blogs.msdn.com/photos/jjameson/images/9899443/500x293.aspx"&gt; 
&lt;DIV class=caption&gt;Figure 5: Installing the RC1 version to TEST&lt;/DIV&gt;
&lt;DIV class=imageLink&gt;&lt;A href="http://blogs.msdn.com/photos/jjameson/images/9899443/original.aspx" target=_blank mce_href="http://blogs.msdn.com/photos/jjameson/images/9899443/original.aspx"&gt;See full-sized image.&lt;/A&gt; &lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;Note that if issues are discovered with the RC1 build, it may be necessary to promote yet another build to the TEST environment, as illustrated in Figure 6.&lt;/P&gt;
&lt;DIV class=image&gt;&lt;IMG title="" alt="" src="http://blogs.msdn.com/photos/jjameson/images/9899444/500x293.aspx" width=500 height=293 mce_src="http://blogs.msdn.com/photos/jjameson/images/9899444/500x293.aspx"&gt; 
&lt;DIV class=caption&gt;Figure 6: Installing the RC2 version to TEST&lt;/DIV&gt;
&lt;DIV class=imageLink&gt;&lt;A href="http://blogs.msdn.com/photos/jjameson/images/9899444/original.aspx" target=_blank mce_href="http://blogs.msdn.com/photos/jjameson/images/9899444/original.aspx"&gt;See full-sized image.&lt;/A&gt; &lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;Assume that the second release candidate (version &lt;STRONG&gt;1.0.379.0 &lt;/STRONG&gt;in Figure 6) passes all of the test cases. The final step is to install the solution into the production environment, as illustrated in Figure 7.&lt;/P&gt;
&lt;DIV class=image&gt;&lt;IMG title="" alt="" src="http://blogs.msdn.com/photos/jjameson/images/9899445/500x293.aspx" width=500 height=293 mce_src="http://blogs.msdn.com/photos/jjameson/images/9899445/500x293.aspx"&gt; 
&lt;DIV class=caption&gt;Figure 7: Installing the V1.0 release to PROD&lt;/DIV&gt;
&lt;DIV class=imageLink&gt;&lt;A href="http://blogs.msdn.com/photos/jjameson/images/9899445/original.aspx" target=_blank mce_href="http://blogs.msdn.com/photos/jjameson/images/9899445/original.aspx"&gt;See full-sized image.&lt;/A&gt; &lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;Note the following key concepts illustrated in the previous figure:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Release Management – not the Test team – is responsible for installing the solution into the PROD environment.&lt;/LI&gt;
&lt;LI&gt;The build installed into PROD was previously installed and evaluated in the DEV and TEST environments.&lt;/LI&gt;
&lt;LI&gt;Before installing the selected build to the PROD environment, the corresponding label in the source control system is annotated – as indicated by &lt;STRONG&gt;(V1.0)&lt;/STRONG&gt; in Figure 7. The Development team also creates a branch in the source control system from this version in order to support “hotfixes” (patches) and minor releases (e.g. V1.1).&lt;/LI&gt;
&lt;LI&gt;Release Management installs the solution in the PROD environment by following the installation guide (which details the install scripts and configuration steps to be used) just as the Test team did when installing the solution into the TEST environment.&lt;/LI&gt;&lt;/UL&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9899878" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx">Core Development</category></item><item><title>Best Practices for SCM and the Daily Build Process</title><link>http://blogs.msdn.com/jjameson/archive/2009/09/26/best-practices-for-scm-and-the-daily-build-process.aspx</link><pubDate>Sat, 26 Sep 2009 19:12:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9899876</guid><dc:creator>Jeremy Jameson</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/jjameson/comments/9899876.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jjameson/commentrss.aspx?PostID=9899876</wfw:commentRss><description>&lt;P&gt;In a previous post, I briefly discussed &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/02/10/branching-strategy-in-team-foundation-server.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/02/10/branching-strategy-in-team-foundation-server.aspx"&gt;a simple branching strategy for Team Foundation Server&lt;/A&gt; (TFS). This was somewhat of a follow-up to another &lt;A href="http://blogs.msdn.com/jjameson/archive/2007/04/18/structure-visual-studio-solutions.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2007/04/18/structure-visual-studio-solutions.aspx"&gt;post&lt;/A&gt; in which I briefly referenced a great article titled &lt;A href="http://downloads.seapine.com/pub/papers/SCMBranchingModels.pdf" mce_href="http://downloads.seapine.com/pub/papers/SCMBranchingModels.pdf"&gt;The Importance of Branching Models in SCM&lt;/A&gt;. If you haven't read this article, I highly recommend it.&lt;/P&gt;
&lt;P&gt;However, while branching is certainly an important aspect of Software Configuration Management (SCM) -- and perhaps one of the most important aspects -- it's certainly not the only one that warrants discussion. In this post, I want to cover some other best practices for SCM as well as the daily build process.&lt;/P&gt;
&lt;P&gt;For example, if you are using TFS, you know that each TFS project typically has a source control repository as well as a project team site in SharePoint (a.k.a. the "Project Portal"). You also probably know that all SharePoint document libraries can be configured to support versioning similar to TFS source control, and thus allow you to, for example, view an old version of an installation guide stored on the Project Portal. However, just because you &lt;EM&gt;can&lt;/EM&gt; do this doesn't mean that it is &lt;EM&gt;recommended &lt;/EM&gt;as a best practice&lt;EM&gt;.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;Note that I'm not saying you should not store any documents on the Project Portal, nor am I saying that you should never enable versioning on document libraries in the Project Portal.&lt;/P&gt;
&lt;P&gt;On the contrary, the Project Portal provides a great place to store documents that various project stakeholders need to access from time to time (without going through Visual Studio or TFS Web Access), and I almost always recommend enabling versioning on all document libraries in your SharePoint sites (provided you have plenty of storage on the backend SQL Server, of course).&lt;/P&gt;
&lt;P&gt;Enabling versions on document libraries provides the ability to go back and see who changed a document and when (which is sort of like an "audit trail" on a document). While you could use the SharePoint versioning feature to go "back in time" in order to view the state of a document (e.g. an installation guide) for a particular version or build of your solution, this would obviously involve a good deal of considerable effort based on timestamps.&lt;/P&gt;
&lt;P&gt;A much easier way of correlating a version of a particular document to a particular build of your solution is to actually store the document in source control within TFS. This allows you to quickly retrieve the document version using a changeset number or, more generally, a build label.&lt;/P&gt;
&lt;H5&gt;Build Labels&lt;/H5&gt;
&lt;P&gt;Back in the days of using Visual SourceSafe (VSS) on customer projects, at the beginning of the build process, a label would always be applied to the project in VSS. Since the build label was applied at the top-level project within a branch, it applied to all files in the solution – including the source code, setup files, and automated tests. This ensures that the installation and tests could be repeated for any particular build.&lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Note&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;While VSS certainly provided the ability to retrieve a project based on a particular timestamp, it definitely wasn't easy (the only way that I was ever to do it was through &lt;A href="http://msdn.microsoft.com/en-us/library/asxkfzy4(VS.80).aspx" mce_href="http://msdn.microsoft.com/en-us/library/asxkfzy4(VS.80).aspx"&gt;the SS command line utility&lt;/A&gt;). Thus build labels provided a quick way of getting a snapshot of the code for a particular build.&lt;BR&gt;&lt;BR&gt;With the concept of changesets in TFS -- and the ability to quickly get the code for a specific changeset -- build labels are obviously not as important as they were in VSS. However, regardless of which particular source control system you are using, build labels provide an easy way to identify and retrieve important builds (such as &lt;STRONG&gt;Beta 1&lt;/STRONG&gt;, &lt;STRONG&gt;Beta 2&lt;/STRONG&gt;, &lt;STRONG&gt;RC1&lt;/STRONG&gt;, and &lt;STRONG&gt;v1.0&lt;/STRONG&gt;) or simply specific versions of the solution (e.g. 1.0.57.0).&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;H6&gt;Source Code&lt;/H6&gt;
&lt;P&gt;Applying the build label to the entire solution allows the Development team to obtain all of the source code for a particular build, thereby enabling them to step through the code to debug an issue that may not be reproducible in the latest version of the code.&lt;/P&gt;
&lt;H6&gt;Setup Files&lt;/H6&gt;
&lt;P&gt;In addition to the source code, the files supporting the installation of the solution (such as the install scripts and the installation guide – but not the compiled setup packages) should also stored in the source control system. In this way, the changes to the installation can be tracked from one version to another.&lt;/P&gt;
&lt;H6&gt;Automated Tests&lt;/H6&gt;
&lt;P&gt;Automated tests change as features are added to the solution. Consequently the tests must be matched to a specific build and therefore need to be checked into the source control system (and therefore labeled as part of the correponding build). Automated tests typically include unit tests as well as Build Verification Tests (BVTs).&lt;/P&gt;
&lt;H5&gt;Daily Build Process&lt;/H5&gt;
&lt;P&gt;The build process is a fundamental activity within any software project. In order to ensure success, the build and deployment process needs to conform to a number of basic requirements. If the solution cannot be built directly from its source code then it is not possible to integrate many of the key processes required for successful delivery.&lt;/P&gt;
&lt;P&gt;The following sections describe the steps in the build process and who is responsible for each part of the process:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost&amp;amp;sectionid=5034&amp;amp;bpt=1#Check-Ins" mce_href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost&amp;amp;sectionid=5034&amp;amp;bpt=1#Check-Ins"&gt;Check-Ins&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost&amp;amp;sectionid=5034&amp;amp;bpt=1#Automated_Build_Process" mce_href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost&amp;amp;sectionid=5034&amp;amp;bpt=1#Automated_Build_Process"&gt;Automated Build Process&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost&amp;amp;sectionid=5034&amp;amp;bpt=1#Build_Verification_Tests" mce_href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost&amp;amp;sectionid=5034&amp;amp;bpt=1#Build_Verification_Tests"&gt;Build Verification Tests&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost&amp;amp;sectionid=5034&amp;amp;bpt=1#Smoke_Tests" mce_href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost&amp;amp;sectionid=5034&amp;amp;bpt=1#Smoke_Tests"&gt;Smoke Tests&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost&amp;amp;sectionid=5034&amp;amp;bpt=1#Investigating_Failures" mce_href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost&amp;amp;sectionid=5034&amp;amp;bpt=1#Investigating_Failures"&gt;Investigating Failures&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost&amp;amp;sectionid=5034&amp;amp;bpt=1#Build_Hand-off" mce_href="http://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=NewPost&amp;amp;sectionid=5034&amp;amp;bpt=1#Build_Hand-off"&gt;Build Hand-off&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;H6&gt;&lt;A title=Check-Ins name=Check-Ins&gt;&lt;/A&gt;Check-Ins&lt;/H6&gt;
&lt;P&gt;All code included in a build must be checked into source control before the build process is initiated. All checked-in code must compile and it is the responsibility of the developer who checks in the code to ensure that the solution builds and all files that are needed to build the solution are checked in.&lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Important&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;The source control must not be left in a broken state at any time. If a build breaks, resolving the problem becomes the highest priority.&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Tip&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;You can use the &lt;STRONG&gt;Builds &lt;/STRONG&gt;check-in policy for TFS to ensure the solution compiles before a developer is allowed to check-in a changeset.&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;Each member of the Development team is responsible for ensuring the following: 
&lt;UL&gt;
&lt;LI&gt;Check-ins must not break functionality in the solution. If a developer checks in a change in their area of the code, he or she must not expect another developer to resolve errors caused by the check-in; either the person checking in the code must fix the dependant code when they check-in or the developer must work with the other developer(s) to coordinate the check-in.&lt;/LI&gt;
&lt;LI&gt;The installation process must also be kept in a functional state at all times. Whenever a developer adds a feature, he or she is responsible for making sure that any setup changes are completed as well. Feature owners are ultimately responsible for the installation and configuration of their features.&lt;/LI&gt;
&lt;LI&gt;The developer is responsible for writing any custom installation actions needed to deploy their feature, for knowing what files need to be deployed on which server, and what permissions the feature needs to run.&lt;/LI&gt;
&lt;LI&gt;The installation of the feature should be completed when the code is checked into source control. The development of any custom installation actions needs to be done in conjunction with the team lead(s), and should not be done in isolation.&lt;/LI&gt;
&lt;LI&gt;Changes to the installation should be checked in to give the team sufficient time to test the changes before the next scheduled build.&lt;/LI&gt;
&lt;LI&gt;Unit tests must pass in the local developer’s environment (LOCAL) before a check-in is performed. If the unit tests are broken because of changes to the feature’s functionality, the developer must resolve the failures -- or reach agreement with the rest of the Development team to disable certain tests until they can be fixed (which should be a rare occurrence).&lt;/LI&gt;&lt;/UL&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Tip&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;You can use the &lt;STRONG&gt;Testing Policy &lt;/STRONG&gt;check-in policy for TFS to ensure that specific unit tests pass before a developer is allowed to check-in a changeset.&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;If any of the above conditions cannot be met, the code should not be checked into source control.&lt;/P&gt;
&lt;H6&gt;&lt;A title=Automated_Build_Process name=Automated_Build_Process&gt;&lt;/A&gt;Automated Build Process&lt;/H6&gt;
&lt;P&gt;The automated build process should:&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;Automatically increment the Build Number or Revision portion of the &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/04/03/best-practices-for-net-assembly-versioning.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/04/03/best-practices-for-net-assembly-versioning.aspx"&gt;assembly version&lt;/A&gt; (depending on which branch is being built)&lt;/LI&gt;
&lt;LI&gt;Apply a build label (if appropriate)&lt;/LI&gt;
&lt;LI&gt;Retrieve the code from the source control system&lt;/LI&gt;
&lt;LI&gt;Compile the solution&lt;/LI&gt;
&lt;LI&gt;Run any associated unit tests&lt;/LI&gt;
&lt;LI&gt;Copy the build to the &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/09/25/development-and-build-environments.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/09/25/development-and-build-environments.aspx"&gt;Release Server&lt;/A&gt;&lt;/LI&gt;&lt;/OL&gt;
&lt;P&gt;If an error occurs during the build -- including execution of the unit tests -- the entire process stops. In this event, an email detailing the error should be mailed to the appropriate distribution list. Once the error is fixed, the build can be restarted. Note that the build/revision number should be incremented for the restarted build.&lt;/P&gt;
&lt;H6&gt;&lt;A title=Build_Verification_Tests name=Build_Verification_Tests&gt;&lt;/A&gt;Build Verification Tests&lt;/H6&gt;
&lt;P&gt;Build Verification Tests (BVTs) are a quick, automated test run on the solution to catch defects in the code. The BVTs should cover the major functionality of the solution but are not meant to be a full regression of all the functionality in the solution.&lt;/P&gt;
&lt;P&gt;The time required to run the entire set of BVTs should be on the order of minutes -- not hours. Otherwise the tests become too cumbersome to run on a regular basis. [Note that this guideline obviously depends on the size of your solution and the resources involved. For example, I believe the BVTs used by the Windows team actually run for several hours, due to the size of the code base. However, it is still short enough to repeat on a daily basis.]&lt;/P&gt;
&lt;P&gt;BVTs are owned by the Test team in conjunction with the Development team to verify the build has completed successfully and to catch any regressions that are introduced as a result of changes to the solution. BVTs should be launched immediately after the automated build and deployment process. The BVTs must return an error to indicate if they have succeeded or failed. Only after the BVTs have passed should the build be considered ready for additional testing by the Test team.&lt;/P&gt;
&lt;P&gt;As noted before, BVTs are owned by Test. The Test team should work closely with Development to keep the BVTs in sync with the changes in the solution. By having the BVTs owned by Test, it ensures that there is a knowledge transfer between Development and Test for any changes to the behavior or architecture of the solution.&lt;/P&gt;
&lt;H6&gt;&lt;A title=Smoke_Tests name=Smoke_Tests&gt;&lt;/A&gt;Smoke Tests&lt;/H6&gt;
&lt;P&gt;In order to successfully deploy the solution, automated tests should be written to survey the environments before and after the application has been deployed. The smoke tests should check that the correct components have been installed, the configuration of the solution has been completed correctly, and that the network connectivity between machines is functioning correctly. The smoke tests must result in a clear pass or fail.&lt;/P&gt;
&lt;P&gt;Smoke tests are generally considered to be more exhaustive than BVTs. The key differentiator is that BVTs are intended to identify whether a build is worthy of additional testing. Ideally, a substantial portion of the testing performed by the Test team is automated -- not manual. So whether you refer to your automated tests as BVTs and consider them part of a "smoke test" is really just a matter of semantics.&lt;/P&gt;
&lt;H6&gt;&lt;A title=Investigating_Failures name=Investigating_Failures&gt;&lt;/A&gt;Investigating Failures&lt;/H6&gt;
&lt;P&gt;When a failure is found with the BVTs or automated smoke tests, the Test team should be the first point of contact to ensure that the tests are correct and the failure is valid.&lt;/P&gt;
&lt;H6&gt;&lt;A title=Build_Hand-off name=Build_Hand-off&gt;&lt;/A&gt;Build Hand-off&lt;/H6&gt;
&lt;P&gt;The Release Management team should always lead the deployment of the solution, with Test and Development provided support as necessary.&lt;/P&gt;
&lt;P&gt;Note that the Development team owns the DEV environment. Consequently, developers will often resort to “tweaking” the environment in order to get the solution deployed and operational. However, in order for the solution to be deployed to TEST, the configuration changes made in DEV must either automated as part of the installation or thoroughly documented as part of the installation guide.&lt;/P&gt;
&lt;H5&gt;Troubleshooting Guide&lt;/H5&gt;
&lt;P&gt;When problems are discovered with the deployment of the solution, a troubleshooting guide should be created (or updated) to capture the experience learned in resolving problems in the solution. The troubleshooting guide is not meant to be exhaustive in terms of troubleshooting all aspects of the solution; however it should provide a baseline for developing the operational support documents for maintaining the solution in the Production environment.&lt;/P&gt;
&lt;P&gt;The troubleshooting guide should capture the process and tools used for investigating the problems with the solution and where to look for logs, events, etc. in the system. It should also capture patterns that have been seen in the solution that point toward a particular fault in the system. &lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Tip&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;A SharePoint site -- or even just a simple SharePoint list -- provides an excellent alternative to a Troubleshooting Guide document. Think of this site --or list -- as a simple "&lt;A href="http://support.microsoft.com/" mce_href="http://support.microsoft.com/"&gt;Knowledge Base&lt;/A&gt;" for your solution.&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9899876" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx">Core Development</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/TFS/default.aspx">TFS</category></item><item><title>Debugging Symbols -- They're Not Just for Debug Builds Anymore</title><link>http://blogs.msdn.com/jjameson/archive/2009/09/26/debugging-symbols-they-re-not-just-for-debug-builds-anymore.aspx</link><pubDate>Sat, 26 Sep 2009 16:20:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9899854</guid><dc:creator>Jeremy Jameson</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/jjameson/comments/9899854.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jjameson/commentrss.aspx?PostID=9899854</wfw:commentRss><description>&lt;P&gt;I started another new project this week.&lt;/P&gt;
&lt;P&gt;Typically one of the first tasks on any new development project is to create a Development Plan that provides consistent guidelines and processes for the Development team. On this new project, another Microsoft consultant had already created a draft of the Development Plan, but in the process of reviewing it, I added some content from a Development Plan that I had created a few years ago.&lt;/P&gt;
&lt;P&gt;In the process of reviewing my old document, I came across the following:&lt;/P&gt;
&lt;BLOCKQUOTE class=directQuote&gt;
&lt;H5&gt;Installation&lt;/H5&gt;... 
&lt;H6&gt;Debug Symbols&lt;/H6&gt;
&lt;P&gt;All Debug builds should create symbol files for debugging purposes. These symbols are included as part of the setup to facilitate debugging in other environments such as DEV.&lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Important &lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;Do not include Debug symbols in the Release configuration of the setup projects.&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;When I read this, I actually let out an audible laugh (okay, I suppose it was more of a chuckle). It must have been the old C++ developer in me that originally put this in the Development Plan (thinking you should never provide PDB files in your Release builds because it makes it all too easy for an outsider to understand your code).&lt;/P&gt;
&lt;P&gt;Well, any .NET developer who has ever fired up Reflector on somebody else's assembly (which hasn't been obfuscated, obviously) knows very well how easy it is to decompile -- er, I mean &lt;EM&gt;disassemble&lt;/EM&gt; -- source code. In fact, regardless of whether you have the PDB files, you can actually debug .NET code -- including setting breakpoints and examining variables -- using tools like &lt;A href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx" mce_href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx"&gt;WinDbg&lt;/A&gt;. I've had to do a little of this in the past and while it's not exactly easy -- especially for a developer who doesn't use WinDbg frequently -- it does help out in a pinch when troubleshooting some nasty problem in Production.&lt;/P&gt;
&lt;P&gt;However, including debugging symbols (i.e. PDB files) in Release builds certainly makes debugging .NET code easier. This is a key point that John Robbins makes in &lt;A href="http://amzn.com/0735622027" mce_href="http://amzn.com/0735622027"&gt;Debugging Microsoft .NET 2.0 Applications&lt;/A&gt;. In fact, here's a direct quote from page 38:&lt;/P&gt;
&lt;BLOCKQUOTE class=directQuote&gt;
&lt;H5&gt;Build All Builds with Debugging Symbols&lt;/H5&gt;...build all builds, including release builds, with full debugging symbols. [...] &lt;/BLOCKQUOTE&gt;
&lt;P&gt;In other words, the Development Plan should say:&lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Important &lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;Always include Debug symbols in the Release configuration of the setup projects -- or, preferably, make them available from a symbol server.&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Regarding John's book...I strongly recommend this book to anyone who considers himself or herself a "serious developer." It is chock full of great tips and recommendations for developing .NET solutions.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9899854" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx">Core Development</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Debugging/default.aspx">Debugging</category></item><item><title>Development and Build Environments</title><link>http://blogs.msdn.com/jjameson/archive/2009/09/25/development-and-build-environments.aspx</link><pubDate>Fri, 25 Sep 2009 15:57:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9899462</guid><dc:creator>Jeremy Jameson</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/jjameson/comments/9899462.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jjameson/commentrss.aspx?PostID=9899462</wfw:commentRss><description>&lt;P&gt;In a previous &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/06/09/environment-naming-conventions.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/06/09/environment-naming-conventions.aspx"&gt;post&lt;/A&gt;, I briefly touched on the "DEV-TEST-PROD" triad of environments that I typically recommend (at a minimum) for every organization doing any form of software development.&lt;/P&gt;
&lt;P&gt;This post describes, in greater detail, the various environments used for developing, building, testing, and deploying a solution. [If you've ever worked on a project with me, you'll find this content is typically found in the Development Plan deliverable.]&lt;/P&gt;
&lt;P&gt;When developing custom solutions, I typically recommend a minimum of four environments:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://blogs.msdn.com/ControlPanel/Blogs/posteditor.aspx?SelectedNavItem=NewPost#Local_Developer_Environments_(LOCAL)" mce_href="http://blogs.msdn.com/ControlPanel/Blogs/posteditor.aspx?SelectedNavItem=NewPost#Local_Developer_Environments_(LOCAL)"&gt;Local Developer Environments (LOCAL)&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://blogs.msdn.com/ControlPanel/Blogs/posteditor.aspx?SelectedNavItem=NewPost#Development_Integration_Environment_(DEV)" mce_href="http://blogs.msdn.com/ControlPanel/Blogs/posteditor.aspx?SelectedNavItem=NewPost#Development_Integration_Environment_(DEV)"&gt;Development Integration Environment (DEV)&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://blogs.msdn.com/ControlPanel/Blogs/posteditor.aspx?SelectedNavItem=NewPost#Test_Environment_(TEST)" mce_href="http://blogs.msdn.com/ControlPanel/Blogs/posteditor.aspx?SelectedNavItem=NewPost#Test_Environment_(TEST)"&gt;Test Environment (TEST)&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://blogs.msdn.com/ControlPanel/Blogs/posteditor.aspx?SelectedNavItem=NewPost#Production_Environment_(PROD)" mce_href="http://blogs.msdn.com/ControlPanel/Blogs/posteditor.aspx?SelectedNavItem=NewPost#Production_Environment_(PROD)"&gt;Production Environment (PROD)&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Since it is assumed that members of the Development team already have individual workstations or laptops, I typically refer to the abbreviated “DEV-TEST-PROD” triad when referencing the various environments.&lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Note&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;For very large development efforts, there may be multiple physical environments corresponding to DEV, TEST, and PROD. For example, numerous “labs” are used within Microsoft for testing various configurations of Windows. However this is not always necessary depending this size of a project. PROD might also refer to multiple physical locations (i.e. for disaster recovery) and depending on release schedules, an additional Maintenance Environment (MAINT) might also be necessary.&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;In addition to describing each environment, this post includes descriptions of the additional servers that are necessary to support the development process. These additional servers include the following:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;A href="http://blogs.msdn.com/ControlPanel/Blogs/posteditor.aspx?SelectedNavItem=NewPost#Build_Server" mce_href="http://blogs.msdn.com/ControlPanel/Blogs/posteditor.aspx?SelectedNavItem=NewPost#Build_Server"&gt;Build Server&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://blogs.msdn.com/ControlPanel/Blogs/posteditor.aspx?SelectedNavItem=NewPost#Source_Control_Server" mce_href="http://blogs.msdn.com/ControlPanel/Blogs/posteditor.aspx?SelectedNavItem=NewPost#Source_Control_Server"&gt;Source Control Server&lt;/A&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;A href="http://blogs.msdn.com/ControlPanel/Blogs/posteditor.aspx?SelectedNavItem=NewPost#Release_Server" mce_href="http://blogs.msdn.com/ControlPanel/Blogs/posteditor.aspx?SelectedNavItem=NewPost#Release_Server"&gt;Release Server&lt;/A&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;H5&gt;&lt;A title=Local_Developer_Environments_(LOCAL) name=Local_Developer_Environments_(LOCAL)&gt;&lt;/A&gt;Local Developer Environments (LOCAL)&lt;/H5&gt;
&lt;P&gt;The “LOCAL” environment refers to the standard machine configuration (or virtual machine configuration) for each developer. It is recommended that this environment have all the applications required for the solution and all the tools required for building and debugging the solution, as well as the standard tools that are needed on the project (such as Microsoft Office).&lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Note&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;Developers must have administrative privileges on their own local environments in order to facilitate development and debugging.&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Most of the functionality for the solution should be able to run in a LOCAL environment. This allows the team members to work independently on their areas of the solution, without having to compete for a single environment resource. The majority of a developer’s assigned functionality should be able to be coded and unit tested in his or her own LOCAL environment. This reduces the contention in larger teams over access to the environments.&lt;/P&gt;
&lt;P&gt;There should be a minimum number of differences between the solution running in a developer’s LOCAL environment and the solution running in the DEV, TEST, or PROD environments. Certain differences are expected, however, as there may be some changes required in order to reduce costs or to emulate the behavior of a shared resource.&lt;/P&gt;
&lt;P&gt;Some organizations use the term “sandbox” instead of LOCAL when referring to this environment. I prefer the term LOCAL since it more accurately reflects the intent of the environment and does not imply that the environment is completely isolated (for example, when integrating with external systems, each developer’s LOCAL environment is often configured to connect to the systems corresponding to the DEV environment).&lt;/P&gt;
&lt;H5&gt;&lt;A title=Development_Integration_Environment_(DEV) name=Development_Integration_Environment_(DEV)&gt;&lt;/A&gt;Development Integration Environment (DEV)&lt;/H5&gt;
&lt;P&gt;The “DEV” environment is similar to each developer’s LOCAL environment. The primary purpose of DEV is to provide an integration environment where the latest build of the complete solution can be evaluated, including all of the various pieces contributed by various members of the Development team. DEV should have all the applications used in the solution and the tools to debug them.&lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Note&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;This environment is owned by the Development team. All members of the Development team (or some subset, depending on the size and experience of the team) have administrative privileges in the DEV environment. Having administrative privileges allows developers to easily debug and reconfigure the environment.&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;After the Build Server finishes compiling the source code, the solution is installed on the DEV environment. This is the first location where the installation process is tested. It is also an important platform for ensuring the basic functionality of the solution works.&lt;/P&gt;
&lt;P&gt;The DEV environment is important for catching problems early on. Any project stakeholder, not just members of the Development team, can use the DEV environment to evaluate the progress of the solution.&lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Important&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;No development should occur on the DEV environment (in other words, no files should ever be checked out directly to the DEV environment). The DEV environment is shared by the entire team and must be treated appropriately as a shared resource. Careful consideration must be made when debugging in this environment (since this will likely interrupt anyone else accessing the DEV environment). Generally speaking, debugging should only take place on the DEV environment when the issue cannot be reproduced in a LOCAL environment. Notification should be provided to the entire team prior to initiating a debugging session directly on the DEV environment (this will also greatly reduce the time required to investigate the issue by avoiding concurrent activities).&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;H5&gt;&lt;A title=Build_Server name=Build_Server&gt;&lt;/A&gt;Build Server&lt;/H5&gt;
&lt;P&gt;The Build Server compiles all the code in the solution and creates the installation. It should have the same configuration as a Local Developer Environment (LOCAL). The Build Server should be dedicated to building the solution and should not contain any unnecessary applications or tools on it. The machine should be kept as clean and stable as possible so that it is in a good state to perform the builds.&lt;/P&gt;
&lt;P&gt;All official builds that are distributed to be tested must be built on the Build Server.&lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Note&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;Depending on the size of the organization and sophistication of the automated build process, a subset of the Development team may need administrative privileges on this server.&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;H5&gt;&lt;A title=Source_Control_Server name=Source_Control_Server&gt;&lt;/A&gt;Source Control Server&lt;/H5&gt;
&lt;P&gt;The source control system should be deployed on a server whose primary purpose is to be the central repository for the source code. This should be dedicated hardware that has sufficient resources to avoid bottlenecks when numerous team members are working concurrently (e.g. 100Mb network connectivity between the source server and the development machines).&lt;/P&gt;
&lt;P&gt;The source control server should perform maintenance checks on a regular basis. Backups should be scheduled at least once daily to ensure that the files can be recovered in the event of a failure. Backups should be kept in a separate location to ensure they can be recovered in case of hardware failure.&lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Note&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;The Development team has limited read-write privileges on this server (i.e. the minimum required for the source control system to function properly).&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;H5&gt;&lt;A title=Release_Server name=Release_Server&gt;&lt;/A&gt;Release Server&lt;/H5&gt;
&lt;P&gt;The Release Server keeps an archive of the output from each successful build. Under the share that is used to archive the solution, there is a folder corresponding to each build. Each build folder contains all of the files necessary to install the solution. There is typically a folder for each project configuration in the solution (e.g. Debug, Release, etc.).&lt;/P&gt;
&lt;P&gt;For example:&lt;/P&gt;
&lt;P&gt;&lt;A href="file://buildserver/Builds/Fabrikam/Project1/1.0.1.0/Debug" mce_href="file://BuildServer/Builds/Fabrikam/Project1/1.0.1.0/Debug"&gt;file://BuildServer/Builds/Fabrikam/Project1/1.0.1.0/Debug&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;In addition to the folders corresponding to each build, there is a folder named &lt;STRONG&gt;Latest&lt;/STRONG&gt; that always contains the most recent successful build. This simplifies the process of installing the solution to the DEV environment.&lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Note&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;All team members should have read-only access to the Builds share. Only the service account used for the build process should have read-write access to the Builds share.&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;The shared folder on the Release Server should be protected by ACLs to ensure that only members of the solution team can access the shares.&lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Important&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;The Test and Release Management teams should only install the solution from the Release Server (or, preferrably, a CD or DVD containing the files from the Release Server). Furthermore, only explicit build folders should be used by the Test and Release Management teams. In other words, the &lt;STRONG&gt;Latest&lt;/STRONG&gt; folder should only be used for automated installs into the DEV environment – it should not be used for installations in the TEST or PROD environments.&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;H5&gt;&lt;A title=Test_Environment_(TEST) name=Test_Environment_(TEST)&gt;&lt;/A&gt;Test Environment (TEST)&lt;/H5&gt;
&lt;P&gt;This environment should mirror the same configuration as the production environment as much as possible. Having an exact replica of the deployed environment ensures that the deployment is correct and repeatable when it goes live. In order to minimize costs, TEST may not always have the same level of fault tolerance as the production environment.&lt;/P&gt;
&lt;P&gt;The primary purpose of TEST is to provide the Test team with an isolated environment for validating test cases. In addition to functional testing, TEST is also used for performance testing and “soak” testing (long-running test scenarios primarily intended to identify resource leaks). Provided the differences between TEST and PROD are only regarding true fault tolerance (and not scale), then performance testing in TEST should accurately predict the performance of PROD.&lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Note&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;This environment is owned by the Test team. No member of the Development team should have privileges in TEST above those of the end users of the solution. Members of the Test team should have the additional privileges necessary to install the solution and assist the Development team with debugging issues in the TEST environment.&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Typically, testers create their test cases and initially regress defects using the DEV environment, however the formal validation of each test case must be performed using the TEST environment.&lt;/P&gt;
&lt;P&gt;Having a separate environment is valuable because it allows the Test team to decide which specific build of the solution should be tested at any given time. “Smoke” tests are typically performed on each build in DEV. Periodically the Test team selects a successful build to promote to TEST.&lt;/P&gt;
&lt;H5&gt;&lt;A title=Production_Environment_(PROD) name=Production_Environment_(PROD)&gt;&lt;/A&gt;Production Environment (PROD)&lt;/H5&gt;
&lt;P&gt;The Production environment is where the solution is ultimately deployed for end users. Strict security procedures must be enforced in this environment.&lt;/P&gt;
&lt;BLOCKQUOTE class=note&gt;
&lt;DIV class=noteTitle&gt;&lt;STRONG&gt;Note&lt;/STRONG&gt;&lt;/DIV&gt;
&lt;DIV&gt;Only the Release Management team should have privileges in PROD above those of the end users of the solution.&lt;/DIV&gt;&lt;/BLOCKQUOTE&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9899462" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jjameson/archive/tags/My+System/default.aspx">My System</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx">Core Development</category></item><item><title>Comparing Source Code Branches</title><link>http://blogs.msdn.com/jjameson/archive/2009/09/16/comparing-source-code-branches.aspx</link><pubDate>Wed, 16 Sep 2009 15:54:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9895837</guid><dc:creator>Jeremy Jameson</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/jjameson/comments/9895837.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jjameson/commentrss.aspx?PostID=9895837</wfw:commentRss><description>&lt;P&gt;During the more than three years I spent helping Agilent Technologies migrate their Internet site from their legacy, proprietary platform to Microsoft Office SharePoint Server (MOSS) 2007, we unfortunately never used Team Foundation Server (TFS). Instead, we used Visual SourceSafe (VSS) in combination with a &lt;A href="http://blogs.msdn.com/jjameson/archive/2008/04/01/tfs-lite-for-wss-v2.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2008/04/01/tfs-lite-for-wss-v2.aspx"&gt;"Work Items" list in SharePoint&lt;/A&gt; that I've described in previous posts.&lt;/P&gt;
&lt;P&gt;While I certainly prefer TFS over VSS, sometimes you simply have to concede that you can't have everything you would like on a customer project and move on to actually getting the work done.&lt;/P&gt;
&lt;P&gt;However, just because we used VSS doesn't mean we didn't follow good Software Configuration Management (SCM) principles. For example, as I've &lt;A href="http://blogs.msdn.com/jjameson/archive/2007/04/18/structure-visual-studio-solutions.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2007/04/18/structure-visual-studio-solutions.aspx"&gt;described in the past&lt;/A&gt;, I insist on using branching right from the start. Thus when I setup the Visual Studio solution for the Agilent project, I created a &lt;STRONG&gt;Main&lt;/STRONG&gt; branch and subsequently created branches for the various releases (e.g. &lt;STRONG&gt;v1.0&lt;/STRONG&gt;, &lt;STRONG&gt;v2.0&lt;/STRONG&gt;, and &lt;STRONG&gt;v3.0&lt;/STRONG&gt;).&lt;/P&gt;
&lt;P&gt;The particular branch that a developer uses would thus depend on whether the changes are for the next major release or a QFE (hotfix) for the version running in Production. For example, after deploying the &lt;A href="http://www.chem.agilent.com/en-US/Support" mce_href="http://www.chem.agilent.com/en-US/Support"&gt;Technical Support site&lt;/A&gt; (i.e. v2.0), we began working on the "General Site" (i.e. v3.0). [Note that in Agilent's terminology, the "General Site" essentially refers to everything outside of Technical Support, the Literature Library, and the Online Store (i.e. the "Buy" tab).]&lt;/P&gt;
&lt;P&gt;However, since we didn't create the &lt;STRONG&gt;v3.0&lt;/STRONG&gt; branch until shortly before the v3.0 release, all v3 ("General Site") development was initially done on the &lt;STRONG&gt;Main&lt;/STRONG&gt; branch -- just like v2 (Tech Support) development was initially done in &lt;STRONG&gt;Main&lt;/STRONG&gt; prior to creating the &lt;STRONG&gt;v2.0 &lt;/STRONG&gt;branch.&lt;/P&gt;
&lt;P&gt;This branching strategy works really well, regardless of which particular SCM system you actually use. The key thing to remember is that all of the changes should eventually make it into the &lt;STRONG&gt;Main&lt;/STRONG&gt; branch (since that branch will eventually be used to create another branch for the next major release).&lt;/P&gt;
&lt;P&gt;The problem with VSS is that while it certainly supports branching, the merging features, um...well, let's just say that they leave a lot to be desired ;-)&lt;/P&gt;
&lt;P&gt;Personally speaking, I've never felt comfortable using the out-of-the-box merging features in VSS, and instead always insisted on merging the changes from one branch to another manually. TFS is obviously years ahead of VSS in terms of branching and merging, but as I said before, sometimes you simply have to deal with what you've got.&lt;/P&gt;
&lt;P&gt;Fortunately, long before the Agilent project, I had previously created my own process that takes a great deal of the "pain" out of manually merging source code. Here is what I came up with.&lt;/P&gt;
&lt;P&gt;In my &lt;A href="http://blogs.msdn.com/jjameson/archive/2007/03/22/backedup-and-notbackedup.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2007/03/22/backedup-and-notbackedup.aspx"&gt;Toolbox&lt;/A&gt;, I have two simple scripts: DiffBranches.cmd and CopyBranch.cmd.&lt;/P&gt;
&lt;P&gt;Here are the contents of DiffBranches.cmd:&lt;/P&gt;
&lt;DIV class=consoleBlock&gt;&lt;PRE&gt;&lt;SAMP&gt;@echo off

setlocal

REM set DIFFTOOL=Windiff.exe
set DIFFTOOL=C:\NotBackedUp\Public\Toolbox\DiffMerge\DiffMerge.exe

set BRANCH1=%1
set BRANCH2=%2

if ("%BRANCH1%") == ("") set BRANCH1=Main

if ("%BRANCH2%") == ("") set BRANCH2=v3.0

call CopyBranch.cmd "%BRANCH1%" "%BRANCH1%_tmp"

call CopyBranch.cmd "%BRANCH2%" "%BRANCH2%_tmp"

"%DIFFTOOL%" "%BRANCH1%_tmp" "%BRANCH2%_tmp"&lt;/SAMP&gt;&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;As you can see, there's not much to it. I simply make temporary copies of the two branches (i.e. by copying the branch folder into a new folder appended with "_tmp") and then use my "Diff Tool" to compare the two folders. Originally, I used WinDiff, but once I &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/03/24/diffmerge-a-better-differencing-tool.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/03/24/diffmerge-a-better-differencing-tool.aspx"&gt;discovered DiffMerge&lt;/A&gt;, I quickly switched to using it exclusively for all of my "diff'ing" activities.&lt;/P&gt;
&lt;P&gt;The real "magic" lies in CopyBranch.cmd:&lt;/P&gt;
&lt;DIV class=consoleBlock&gt;&lt;PRE&gt;&lt;SAMP&gt;@echo off

setlocal

set BRANCH1=%1
set BRANCH2=%2

if ("%BRANCH1%") == ("") set BRANCH1=Main

if ("%BRANCH2%") == ("") set BRANCH2="%BRANCH1%_tmp"

robocopy "%BRANCH1%" "%BRANCH2%" /E /MIR /XD bin obj TestResults /XF *.scc *.suo *.user *.vspscc
&lt;/SAMP&gt;&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;Note that I put the word &lt;EM&gt;magic&lt;/EM&gt; in quotes because it's really not magic at all. When copying a source code branch, I simply use robocopy.exe and specify the following options:&lt;/P&gt;
&lt;TABLE class=accent1 cellSpacing=0 class="accent1"&gt;
&lt;CAPTION&gt;robocoby.exe command-line options used in CopyBranch.cmd&lt;/CAPTION&gt;
&lt;THEAD&gt;
&lt;TR&gt;
&lt;TH&gt;Command-Line Option&lt;/TH&gt;
&lt;TH&gt;Comments&lt;/TH&gt;&lt;/TR&gt;&lt;/THEAD&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD&gt;/E&lt;/TD&gt;
&lt;TD&gt;Copy subdirectories, including empty ones&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;/MIR&lt;/TD&gt;
&lt;TD&gt;Mirror the directory tree, thus ensuring that when I subsequently run CopyBranch.cmd, any deleted files from the original branch are removed from the "temporary" copy of the branch)&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;/XD bin obj TestResults&lt;/TD&gt;
&lt;TD&gt;Exclude directories matching the given names/paths, thus skipping the compiled output (i.e. bin and obj) as well as the test results generated by running unit tests from within Visual Studio&lt;/TD&gt;&lt;/TR&gt;
&lt;TR&gt;
&lt;TD&gt;/XF *.scc *.suo *.user *.vspscc &lt;/TD&gt;
&lt;TD&gt;Exclude files matching the given names/paths/wildcards, thus skipping source code control files (*.scc and *.vspscc), and Visual Studio solution/project user-specific options (i.e. *.suo and *.user)&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;
&lt;P&gt;For example, let's suppose that I've checked in some changes to the &lt;STRONG&gt;v3.0 &lt;/STRONG&gt;branch that need to be propagated to the &lt;STRONG&gt;Main &lt;/STRONG&gt;branch. I would open a command prompt and run the following:&lt;/P&gt;
&lt;DIV class=consoleBlock&gt;&lt;PRE&gt;&lt;SAMP&gt;C:\NotBackedUp\Agilent&amp;gt;DiffBranches.cmd v3.0 Main&lt;/SAMP&gt;&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;After the two branches are copied to their respective temporary folders, DiffMerge.exe is launched to compare the two branches. Since I exclude many of the directories and files that are &lt;EM&gt;expected&lt;/EM&gt; to differ between the two branches, I can quickly view only the differences that I am interested in. I can even use DiffMerge.exe to apply the changes interactively (checking out the files to be updated beforehand as necessary). This greatly reduces the effort involved in manually merging changes from one branch into another.&lt;/P&gt;
&lt;P&gt;Note that it takes a little bit of time to copy a branch the first time, but this is lightning fast on subsequent runs. Hence why I don't delete the "_tmp" folders after comparing two branches.&lt;/P&gt;
&lt;P&gt;I occasionally use this process even on projects where we've used Team Foundation Server. For example, I sometimes create a new workspace in TFS to represent a "temporary branch" where I want to experiment with some substantial changes to the source code (while I still have pending changes in my main workspace, that I may have shelved but don't want to check-in just yet). Using a little robocopy.exe and DiffMerge.exe, I can more easily compare two branches or workspaces.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9895837" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jjameson/archive/tags/My+System/default.aspx">My System</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx">Core Development</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Visual+Studio/default.aspx">Visual Studio</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/TFS/default.aspx">TFS</category></item><item><title>Using SysPrep'ed VHDs for New Hyper-V Virtual Machines</title><link>http://blogs.msdn.com/jjameson/archive/2009/08/13/using-sysprep-ed-vhds-for-new-hyper-v-virtual-machines.aspx</link><pubDate>Thu, 13 Aug 2009 18:16:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9868402</guid><dc:creator>Jeremy Jameson</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/jjameson/comments/9868402.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jjameson/commentrss.aspx?PostID=9868402</wfw:commentRss><description>&lt;P&gt;As noted in my &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/08/13/sharepoint-2010-sneak-peek.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/08/13/sharepoint-2010-sneak-peek.aspx"&gt;previous post&lt;/A&gt;, I spent 7 days in "alpha" training last week for SharePoint 2010.&lt;/P&gt;
&lt;P&gt;Consequently, one of my goals for this week was to update my "dogfood" VM with the CTP build of SharePoint Server 2010, so that I can continue building on the foundation of what I learned last week and dive deeper into the new features of the product.&lt;/P&gt;
&lt;P&gt;This is the quintessential scenario for why I love virtual machines. I can quickly "spin up" a new VM and then proceed to load various products such as SQL Server 2008, SharePoint Server 2010, and Visual Studio 2010; and, since it's isolated in a VM, there's no risk with exploring early, pre-release builds of software.&lt;/P&gt;
&lt;P&gt;Note that I don't start from scratch each time I need to create a new VM. Rather, I start from a SysPrep'ed image of the particular operating system that I want to use.&lt;/P&gt;
&lt;P&gt;In this case, I copied my ws2008-std-x64.vhd (Windows Server 2008 Standard x64 with Service Pack 2) over to the folder for my DOGFOOD VM and renamed it -- yep, you guessed it -- dogfood.vhd.&lt;/P&gt;
&lt;P&gt;I then proceeded to start the DOGFOOD VM using Hyper-V Manager. Unfortunately, I encountered the following error:&lt;/P&gt;
&lt;BLOCKQUOTE class="directQuote errorMessage"&gt;Virtual Machine Connection&lt;BR&gt;&lt;BR&gt;The application encountered an error while attempting to change the state of 'dogfood'.&lt;BR&gt;&lt;BR&gt;'dogfood' failed to start.&lt;BR&gt;&lt;BR&gt;Microsoft Emulated IDE Controller (Instance ID {GUID}): Failed to power on with Error 'General access denied error'&lt;BR&gt;&lt;BR&gt;IDE/ATAPI: Could not attach 'C:\NotBackedUp\VMs\dogfood\dogfood.vhd' to location 0/0 of IDE Controller. Error: 'General access denied error'&lt;BR&gt;&lt;BR&gt;The file 'C:\NotBackedUp\VMs\dogfood\dogfood.vhd' does not have the required security settings. Error: 'General access denied error'&lt;/BLOCKQUOTE&gt;
&lt;P&gt;Using the cacls.exe utility, I examined the permissions specified for a VHD used by one of the other VMs that was already running on the same server. I found the following:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;NT VIRTUAL MACHINE\48FEF7FD-04D0-4AFF-B6F F-4F0D159DC40E:(special access:) 
&lt;UL&gt;
&lt;LI&gt;READ_CONTROL&lt;/LI&gt;
&lt;LI&gt;SYNCHRONIZE&lt;/LI&gt;
&lt;LI&gt;FILE_GENERIC_READ&lt;/LI&gt;
&lt;LI&gt;FILE_GENERIC_WRITE &lt;/LI&gt;
&lt;LI&gt;FILE_READ_DATA &lt;/LI&gt;
&lt;LI&gt;FILE_WRITE_DATA &lt;/LI&gt;
&lt;LI&gt;FILE_APPEND_DATA &lt;/LI&gt;
&lt;LI&gt;FILE_READ_EA &lt;/LI&gt;
&lt;LI&gt;FILE_WRITE_EA &lt;/LI&gt;
&lt;LI&gt;FILE_READ_ATTRIBUTES &lt;/LI&gt;
&lt;LI&gt;FILE_WRITE_ATTRIBUTES &lt;/LI&gt;&lt;/UL&gt;&lt;/LI&gt;
&lt;LI&gt;NT AUTHORITY\SYSTEM:(ID)F&lt;/LI&gt;
&lt;LI&gt;BUILTIN\Administrators:(ID)F&lt;/LI&gt;
&lt;LI&gt;BUILTIN\Users:(ID)R &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Note that the list of discrete permissions listed for the NT VIRTUAL MACHINE service account essentially equates to Read and Write, as observed by running the new icacls.exe tool introduced in Windows Server 2003 SP2, and also included in Windows Vista and Windows Server 2008.&lt;/P&gt;
&lt;P&gt;Consequently, you can specify a command like the following to grant permissions on the VHD to the service account used by Hyper-V:&lt;/P&gt;
&lt;DIV class=consoleBlock&gt;icacls dogfood.vhd /grant "NT VIRTUAL MACHINE\C60995EB-8B7D-46DB-BD1E-3638CD1AEC32":(R,W)&lt;/DIV&gt;
&lt;P&gt;Note that the GUID varies with each VM, so you'll need to tweak this accordingly for your environment. To find the GUID to use, examine the &lt;STRONG&gt;Virtual Machines &lt;/STRONG&gt;folder for the VM.&lt;/P&gt;
&lt;P&gt;Also note that you may need to use the VM settings to remove the VHD from the IDE controller and subsequently re-add it (in other words, it looks like Hyper-V does not recognize that the file permissions have been updated in the background).&lt;/P&gt;
&lt;P&gt;It takes about 10 minutes to copy the SysPrep'ed VHD, which is obviously much, much faster than the time it takes to install Windows Server 2008 from scratch (especially when you take patching into account). Overall, it takes me about 25-30 minutes to spin up a new Windows Server 2008 VM, which includes joining it to my Active Directory domain and getting all of the latest patches applied using Windows Server Update Services (which, in the &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/09/14/the-jameson-datacenter.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/09/14/the-jameson-datacenter.aspx"&gt;"Jameson Datacenter"&lt;/A&gt; is enforced through Group Policy).&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9868402" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jjameson/archive/tags/My+System/default.aspx">My System</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx">Core Development</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Virtualization/default.aspx">Virtualization</category></item><item><title>Configuring Logging in ASP.NET Applications (and SharePoint)</title><link>http://blogs.msdn.com/jjameson/archive/2009/06/18/configuring-logging-in-asp-net-applications-and-sharepoint.aspx</link><pubDate>Fri, 19 Jun 2009 04:38:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9777795</guid><dc:creator>Jeremy Jameson</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/jjameson/comments/9777795.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jjameson/commentrss.aspx?PostID=9777795</wfw:commentRss><description>&lt;P&gt;This post continues on the original post for my &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/06/18/a-simple-but-highly-effective-approach-to-logging.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/06/18/a-simple-but-highly-effective-approach-to-logging.aspx"&gt;simple, but highly effective approach to logging&lt;/A&gt; and the follow-up post which introduced &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/06/18/configuring-logging-in-a-console-application.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/06/18/configuring-logging-in-a-console-application.aspx"&gt;configuring logging for console applications&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;Obviously not all solutions are simple console-based applications. With ASP.NET Web services and applications -- including Microsoft Office SharePoint Server (MOSS) and Windows SharePoint Services (WSS) -- you can still view log messages from the &lt;CODE&gt;Logger&lt;/CODE&gt; class very easily on a per-request basis.&lt;/P&gt;
&lt;P&gt;Note that the &lt;A href="http://msdn.microsoft.com/en-us/library/system.web.webpagetracelistener.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.web.webpagetracelistener.aspx"&gt;System.Web.WebPageTraceListener&lt;/A&gt; can be specified in Web.config to enable logging to the ASP.NET tracing feature:&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;CODE&gt;&lt;PRE&gt;&lt;SPAN style="COLOR: #0000ff"&gt;  &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;system.diagnostics&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sources&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;source&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;defaultTraceSource&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;switchName&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;allTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
        &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;listeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
          &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;webPageTraceListener&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
        &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;listeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;source&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sources&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sharedListeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;type&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;System.Web.WebPageTraceListener, System.Web, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a&lt;/SPAN&gt;"
&lt;SPAN style="COLOR: #ff0000"&gt;        name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;webPageTraceListener&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;traceOutputOptions&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;None&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
    &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sharedListeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;switches&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;allTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;All&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;verboseTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Verbose&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;infoTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Info&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;warningTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Warning&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;errorTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Error&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;offTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Off&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
    &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;switches&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
  &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;system.diagnostics&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/CODE&gt;&lt;/DIV&gt;
&lt;P&gt;Also note that ASP.NET tracing must be enabled using the &lt;CODE&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;trace&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/CODE&gt; element within &lt;CODE&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;system.web&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/CODE&gt;:&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;CODE&gt;&lt;PRE&gt;&lt;SPAN style="COLOR: #0000ff"&gt;  &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;system.web&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;trace&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;enabled&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;pageOutput&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;requestLimit&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;50&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;localOnly&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
  &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;system.web&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/CODE&gt;&lt;/DIV&gt;
&lt;P&gt;Be sure to set the &lt;CODE&gt;&lt;SPAN style="COLOR: #ff0000"&gt;requestLimit&lt;/SPAN&gt;&lt;/CODE&gt; high enough to enable access to the page trace you are interested, but also be aware that you can easily clear the captured traces and then browse to the page of interest again.&lt;/P&gt;
&lt;P&gt;Once configured, browse to the page on the site. Then modify the URL to browse to Trace.axd (e.g. &lt;A href="http://fabrikam-local/Trace.axd" mce_href="http://fabrikam-local/Trace.axd"&gt;http://fabrikam-local/Trace.axd&lt;/A&gt;) to display the Trace Viewer.&lt;/P&gt;
&lt;DIV class=image&gt;&lt;IMG title="" alt="" src="http://blogs.msdn.com/photos/jjameson/images/9776165/500x223.aspx" width=500 height=223 mce_src="http://blogs.msdn.com/photos/jjameson/images/9776165/500x223.aspx"&gt; 
&lt;DIV class=caption&gt;Figure 1: ASP.NET Trace Viewer&lt;/DIV&gt;
&lt;DIV class=imageLink&gt;&lt;A href="http://blogs.msdn.com/photos/jjameson/images/9776165/original.aspx" target=_blank mce_href="http://blogs.msdn.com/photos/jjameson/images/9776165/original.aspx"&gt;See full-sized image.&lt;/A&gt; &lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;Locate the request that you want to view log messages for and click the corresponding &lt;STRONG&gt;View Details &lt;/STRONG&gt;link.&lt;/P&gt;
&lt;DIV class=image&gt;&lt;IMG title="" alt="" src="http://blogs.msdn.com/photos/jjameson/images/9776168/379x480.aspx" width=379 height=480 mce_src="http://blogs.msdn.com/photos/jjameson/images/9776168/379x480.aspx"&gt; 
&lt;DIV class=caption&gt;Figure 2: ASP.NET Trace Viewer&lt;/DIV&gt;
&lt;DIV class=imageLink&gt;&lt;A href="http://blogs.msdn.com/photos/jjameson/images/9776168/original.aspx" target=_blank mce_href="http://blogs.msdn.com/photos/jjameson/images/9776168/original.aspx"&gt;See full-sized image.&lt;/A&gt; &lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;Notice that the &lt;A href="http://msdn.microsoft.com/en-us/library/system.web.webpagetracelistener.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.web.webpagetracelistener.aspx"&gt;WebPageTraceListener&lt;/A&gt; even formatted the warning message in red. How cool is that?! [For all you SharePoint developers out there, compare this with "diving" into the ULS logs to find an error or warning for a particular page request!]&lt;/P&gt;
&lt;P&gt;Be aware that the Web.config file you use for SharePoint applications varies depending on whether you want to view log messages for a content page or for an application (i.e. _layouts) page. This is covered in my &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/06/18/configuring-logging-in-sharepoint-application-pages.aspx"&gt;next post&lt;/A&gt;.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9777795" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jjameson/archive/tags/Simplify/default.aspx">Simplify</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/MOSS+2007/default.aspx">MOSS 2007</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx">Core Development</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/WSS+v3/default.aspx">WSS v3</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Web+Development/default.aspx">Web Development</category></item><item><title>Configuring Logging in a Console Application</title><link>http://blogs.msdn.com/jjameson/archive/2009/06/18/configuring-logging-in-a-console-application.aspx</link><pubDate>Fri, 19 Jun 2009 03:50:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9777215</guid><dc:creator>Jeremy Jameson</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/jjameson/comments/9777215.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jjameson/commentrss.aspx?PostID=9777215</wfw:commentRss><description>&lt;P&gt;In my previous post, I introduced my &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/06/18/a-simple-but-highly-effective-approach-to-logging.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/06/18/a-simple-but-highly-effective-approach-to-logging.aspx"&gt;simple, but highly effective approach to logging&lt;/A&gt;. As promised, this post introduces how to configure logging (based on a simple console application).&lt;/P&gt;
&lt;P&gt;As noted in my previous post, one or more &lt;A href="http://msdn.microsoft.com/en-us/library/system.diagnostics.tracelistener(VS.80).aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.diagnostics.tracelistener(VS.80).aspx"&gt;trace listeners&lt;/A&gt; can be configured for a particular &lt;A href="http://msdn.microsoft.com/en-us/library/system.diagnostics.tracesource(VS.80).aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.diagnostics.tracesource(VS.80).aspx"&gt;System.Diagnostics.TraceSource&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;To understand the configuration of various trace listeners, consider the following console application:&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;CODE&gt;&lt;PRE&gt;&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.Diagnostics;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.Globalization;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.Text;

&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; Fabrikam.Demo.CoreServices.Logging;

&lt;SPAN style="COLOR: #0000ff"&gt;namespace&lt;/SPAN&gt; Fabrikam.Demo.AdminConsole
{
    &lt;SPAN style="COLOR: #0000ff"&gt;class&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;Program
&lt;/SPAN&gt;    {
        &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; Main(
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;[] args)
        {
            &lt;SPAN style="COLOR: #0000ff"&gt;try
&lt;/SPAN&gt;            {
                LogCommandLine(&lt;SPAN style="COLOR: #a31515"&gt;"AdminConsole.exe"&lt;/SPAN&gt;, args);

                &lt;SPAN style="COLOR: #008000"&gt;// Parse the command line arguments and initialize the work
&lt;/SPAN&gt;                &lt;SPAN style="COLOR: #008000"&gt;// ...

&lt;/SPAN&gt;                &lt;SPAN style="COLOR: #008000"&gt;// Process the work
&lt;/SPAN&gt;                Process();
            }
            &lt;SPAN style="COLOR: #0000ff"&gt;catch&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #2b91af"&gt;Exception&lt;/SPAN&gt; ex)
            {
                &lt;SPAN style="COLOR: #2b91af"&gt;Logger&lt;/SPAN&gt;.LogCritical(ex.Message + &lt;SPAN style="COLOR: #a31515"&gt;"\n"&lt;/SPAN&gt; + ex.StackTrace );
                &lt;SPAN style="COLOR: #2b91af"&gt;Logger&lt;/SPAN&gt;.Flush();
                &lt;SPAN style="COLOR: #2b91af"&gt;Environment&lt;/SPAN&gt;.Exit(1);
            }

            &lt;SPAN style="COLOR: #2b91af"&gt;Logger&lt;/SPAN&gt;.LogInfo(&lt;SPAN style="COLOR: #a31515"&gt;"Program complete."&lt;/SPAN&gt;);
            &lt;SPAN style="COLOR: #2b91af"&gt;Logger&lt;/SPAN&gt;.Flush();
        }

        &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; LogCommandLine(
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; program,
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;[] args)
        {
            &lt;SPAN style="COLOR: #2b91af"&gt;Debug&lt;/SPAN&gt;.Assert(&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.IsNullOrEmpty(program) == &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;);
            &lt;SPAN style="COLOR: #2b91af"&gt;Debug&lt;/SPAN&gt;.Assert(args != &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;);

            &lt;SPAN style="COLOR: #2b91af"&gt;StringBuilder&lt;/SPAN&gt; commandLineBuilder = &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;StringBuilder&lt;/SPAN&gt;(program);
            &lt;SPAN style="COLOR: #0000ff"&gt;for&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; i = 0; i &amp;lt; args.Length; i++)
            {
                commandLineBuilder.Append(&lt;SPAN style="COLOR: #a31515"&gt;" "&lt;/SPAN&gt;);
                commandLineBuilder.Append(args[i]);
            }

            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; commandLine = commandLineBuilder.ToString();
            &lt;SPAN style="COLOR: #2b91af"&gt;Logger&lt;/SPAN&gt;.LogInfo(commandLine);
        }        

        &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; Process()
        {
            &lt;SPAN style="COLOR: #2b91af"&gt;Logger&lt;/SPAN&gt;.LogDebug(&lt;SPAN style="COLOR: #a31515"&gt;"Starting processing..."&lt;/SPAN&gt;);
            
            &lt;SPAN style="COLOR: #008000"&gt;// Simulate the processing of a work item queue.
&lt;/SPAN&gt;            &lt;SPAN style="COLOR: #0000ff"&gt;for&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; i = -1; i &amp;lt;= 4; i++)
            {
                ProcessWorkItem(i);
            }            

            &lt;SPAN style="COLOR: #2b91af"&gt;Logger&lt;/SPAN&gt;.LogInfo(&lt;SPAN style="COLOR: #a31515"&gt;"Successfully completed processing."&lt;/SPAN&gt;);
        }
        &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; ProcessWorkItem(
            &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; workItemId)
        {
            &lt;SPAN style="COLOR: #008000"&gt;// If an error occurs processing a work item, we want to
&lt;/SPAN&gt;            &lt;SPAN style="COLOR: #008000"&gt;// log a warning, but continue processing the next work item.
&lt;/SPAN&gt;            &lt;SPAN style="COLOR: #0000ff"&gt;try
&lt;/SPAN&gt;            {
                &lt;SPAN style="COLOR: #008000"&gt;// Simulate processing of the work item by simply
&lt;/SPAN&gt;                &lt;SPAN style="COLOR: #008000"&gt;// showing the square root of the work item Id.
&lt;/SPAN&gt;                ShowSquareRoot(workItemId);
            }
            &lt;SPAN style="COLOR: #0000ff"&gt;catch&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #2b91af"&gt;ArgumentException&lt;/SPAN&gt; ex)
            {
                &lt;SPAN style="COLOR: #2b91af"&gt;Logger&lt;/SPAN&gt;.LogWarning(
                    &lt;SPAN style="COLOR: #2b91af"&gt;CultureInfo&lt;/SPAN&gt;.InvariantCulture,
                    &lt;SPAN style="COLOR: #a31515"&gt;"Unable to process work item {0} ({1})."&lt;/SPAN&gt;,
                    workItemId,
                    ex.Message);
            }
        }

        &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; ShowSquareRoot(
            &lt;SPAN style="COLOR: #0000ff"&gt;double&lt;/SPAN&gt; d)
        {
            &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (d &amp;lt; 0.0)
            {
                &lt;SPAN style="COLOR: #0000ff"&gt;throw&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;ArgumentException&lt;/SPAN&gt;(
                    &lt;SPAN style="COLOR: #a31515"&gt;"The value must be greater than or equal to zero."&lt;/SPAN&gt;,
                    &lt;SPAN style="COLOR: #a31515"&gt;"d"&lt;/SPAN&gt;);
            }


            &lt;SPAN style="COLOR: #2b91af"&gt;Logger&lt;/SPAN&gt;.LogDebug(
                &lt;SPAN style="COLOR: #2b91af"&gt;CultureInfo&lt;/SPAN&gt;.InvariantCulture,
                &lt;SPAN style="COLOR: #a31515"&gt;"Computing square root of {0}..."&lt;/SPAN&gt;,
                d);

            &lt;SPAN style="COLOR: #0000ff"&gt;double&lt;/SPAN&gt; sqrt = &lt;SPAN style="COLOR: #2b91af"&gt;Math&lt;/SPAN&gt;.Sqrt(d);
            &lt;SPAN style="COLOR: #2b91af"&gt;Debug&lt;/SPAN&gt;.Assert(&lt;SPAN style="COLOR: #0000ff"&gt;double&lt;/SPAN&gt;.IsNaN(sqrt) == &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;);

            &lt;SPAN style="COLOR: #2b91af"&gt;Console&lt;/SPAN&gt;.WriteLine(
                &lt;SPAN style="COLOR: #a31515"&gt;"The square root of {0} is {1:0.000}."&lt;/SPAN&gt;,
                d,
                sqrt);
        }
    }
}
&lt;/PRE&gt;&lt;/CODE&gt;&lt;/DIV&gt;
&lt;P&gt;Running this program without configuring any trace listeners results in the following output to the console:&lt;/P&gt;
&lt;DIV class=consoleBlock&gt;&lt;SAMP&gt;The square root of 0 is 0.000.&lt;BR&gt;The square root of 1 is 1.000.&lt;BR&gt;The square root of 2 is 1.414.&lt;BR&gt;The square root of 3 is 1.732.&lt;BR&gt;The square root of 4 is 2.000.&lt;/SAMP&gt;&lt;/DIV&gt;
&lt;P&gt;Notice that none of the log messages are displayed in the console output.&lt;/P&gt;
&lt;P&gt;However, if we start &lt;A href="http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx" mce_href="http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx"&gt;DebugView&lt;/A&gt; before running the program, then we can easily view all of the log messages.&lt;/P&gt;
&lt;DIV class=image&gt;&lt;IMG title="" alt="" src="http://blogs.msdn.com/photos/jjameson/images/9776163/500x159.aspx" width=500 height=159 mce_src="http://blogs.msdn.com/photos/jjameson/images/9776163/500x159.aspx"&gt; 
&lt;DIV class=caption&gt;Figure 1: DebugView (a.k.a. Dbgview.exe)&lt;/DIV&gt;
&lt;DIV class=imageLink&gt;&lt;A href="http://blogs.msdn.com/photos/jjameson/images/9776163/original.aspx" target=_blank mce_href="http://blogs.msdn.com/photos/jjameson/images/9776163/original.aspx"&gt;See full-sized image.&lt;/A&gt; &lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;To show the log messages in the console, we simply need to configure a listener. For a console application, this is done using the application configuration file (which is located in the folder with the application executable and has the name of the application with the ".config" file name extension added).&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;CODE&gt;&lt;PRE&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;?&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;xml&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;version&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;1.0&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;encoding&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;utf-8&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; ?&amp;gt;
&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;configuration&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
  &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;system.diagnostics&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sources&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;source&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;defaultTraceSource&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;switchValue&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;All&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
        &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;listeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
          &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;consoleListener&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
          &amp;lt;!--
&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;            Remove the Default listener to avoid duplicate messages
            being sent to the debugger for display
          &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
          &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;remove&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Default&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
        &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;listeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;source&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sources&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sharedListeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add
&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;        &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;type&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;System.Diagnostics.ConsoleTraceListener&lt;/SPAN&gt;"
&lt;SPAN style="COLOR: #0000ff"&gt;        &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;consoleListener&lt;/SPAN&gt;"
&lt;SPAN style="COLOR: #0000ff"&gt;        &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;traceOutputOptions&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;None&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
    &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sharedListeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
  &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;system.diagnostics&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;configuration&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/CODE&gt;&lt;/DIV&gt;
&lt;P&gt;With this configuration, the console output shows:&lt;/P&gt;
&lt;DIV class=consoleBlock&gt;&lt;SAMP&gt;defaultTraceSource Information: 0 : AdminConsole.exe&lt;BR&gt;defaultTraceSource Verbose: 0 : Starting processing...&lt;BR&gt;defaultTraceSource Warning: 0 : Unable to process work item -1 (The value must be greater than or equal to zero.&lt;BR&gt;Parameter name: d).&lt;BR&gt;defaultTraceSource Verbose: 0 : Computing square root of 0...&lt;BR&gt;The square root of 0 is 0.000.&lt;BR&gt;defaultTraceSource Verbose: 0 : Computing square root of 1...&lt;BR&gt;The square root of 1 is 1.000.&lt;BR&gt;defaultTraceSource Verbose: 0 : Computing square root of 2...&lt;BR&gt;The square root of 2 is 1.414.&lt;BR&gt;defaultTraceSource Verbose: 0 : Computing square root of 3...&lt;BR&gt;The square root of 3 is 1.732.&lt;BR&gt;defaultTraceSource Verbose: 0 : Computing square root of 4...&lt;BR&gt;The square root of 4 is 2.000.&lt;BR&gt;defaultTraceSource Information: 0 : Successfully completed processing.&lt;BR&gt;defaultTraceSource Information: 0 : Program complete.&lt;/SAMP&gt;&lt;/DIV&gt;
&lt;P&gt;Notice that &lt;A href="http://msdn.microsoft.com/en-us/library/system.diagnostics.consoletracelistener.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.diagnostics.consoletracelistener.aspx"&gt;System.Diagnostics.ConsoleTraceListener&lt;/A&gt; outputs the name of the TraceSource (which in this case is "defaultTraceSource") as well as the event Id (which, for my simple &lt;CODE&gt;Logger&lt;/CODE&gt; class is always 0). It can also be configured to show other fields, such as thread Id.&lt;/P&gt;
&lt;P&gt;A &lt;A href="http://msdn.microsoft.com/en-us/library/system.diagnostics.traceswitch.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.diagnostics.traceswitch.aspx"&gt;TraceSwitch&lt;/A&gt; can also be configured to control tracing and debug output. For example, the following configuration specifies that the trace source should ignore low-level debugging and information messages, and only show warning and error messages.&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;CODE&gt;&lt;PRE&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;?&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;xml&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;version&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;1.0&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;encoding&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;utf-8&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; ?&amp;gt;
&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;configuration&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
  &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;system.diagnostics&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sources&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;source&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;defaultTraceSource&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;switchName&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;warningTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
        &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;listeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
          &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;consoleListener&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
          &amp;lt;!--
&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;            Remove the Default listener to avoid duplicate messages
            being sent to the debugger for display
          &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
          &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;remove&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Default&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
        &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;listeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;source&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sources&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sharedListeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add
&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;        &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;type&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;System.Diagnostics.ConsoleTraceListener&lt;/SPAN&gt;"
&lt;SPAN style="COLOR: #0000ff"&gt;        &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;consoleListener&lt;/SPAN&gt;"
&lt;SPAN style="COLOR: #0000ff"&gt;        &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;traceOutputOptions&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;None&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
    &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sharedListeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;switches&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;!--&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Use this switch to output all log messages &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;allTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;All&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;!--&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Use this switch to output low-level debugging, informational,
        warning, and error messages &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;verboseTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Verbose&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;!--&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Use this switch to output informational, warning,
        and error messages &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;infoTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Info&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;!--&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Use this switch to output warning and error messages &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;warningTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Warning&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;!--&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Use this switch to output error messages &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;errorTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Error&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;!--&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Use this switch to output no tracing messages &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;offTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Off&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
    &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;switches&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
  &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;system.diagnostics&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;configuration&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/CODE&gt;&lt;/DIV&gt;
&lt;P&gt;With this configuration, the console output is:&lt;/P&gt;
&lt;DIV class=consoleBlock&gt;&lt;SAMP&gt;defaultTraceSource Warning: 0 : Unable to process work item -1 (The value must be greater than or equal to zero.&lt;BR&gt;Parameter name: d).&lt;BR&gt;The square root of 0 is 0.000.&lt;BR&gt;The square root of 1 is 1.000.&lt;BR&gt;The square root of 2 is 1.414.&lt;BR&gt;The square root of 3 is 1.732.&lt;BR&gt;The square root of 4 is 2.000.&lt;/SAMP&gt;&lt;/DIV&gt;
&lt;P&gt;With just a little more configuration, we can specify that we want all log messages to go to the console (for example, so the person running the utility can easily monitor the progress of some long-running operation) but only output information, warning, and error messages to a file (possibly for later review).&lt;/P&gt;
&lt;P&gt;In the following configuration, note the new &lt;CODE&gt;&lt;SPAN style="COLOR: #0000ff"&gt;logFileTraceListener&lt;/SPAN&gt;&lt;/CODE&gt; and the corresponding &lt;CODE&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;filter&amp;gt;&lt;/SPAN&gt;&lt;/CODE&gt; element used to limit the file output to level &lt;CODE&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Information&lt;/SPAN&gt;"&lt;/CODE&gt; (and above -- which includes warning and error messages).&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;CODE&gt;&lt;PRE&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;lt;?&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;xml&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;version&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;1.0&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;encoding&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;utf-8&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; ?&amp;gt;
&amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;configuration&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
  &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;system.diagnostics&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sources&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;source&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;defaultTraceSource&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;switchName&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;allTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
        &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;listeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
          &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;consoleListener&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
          &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;logFileTraceListener&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
          &amp;lt;!--
&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;            Remove the Default listener to avoid duplicate messages
            being sent to the debugger for display
          &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
          &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;remove&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Default&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
        &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;listeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;source&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sources&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sharedListeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add
&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;        &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;type&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;System.Diagnostics.ConsoleTraceListener&lt;/SPAN&gt;"
&lt;SPAN style="COLOR: #0000ff"&gt;        &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;consoleListener&lt;/SPAN&gt;"
&lt;SPAN style="COLOR: #0000ff"&gt;        &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;traceOutputOptions&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;None&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add
&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;        &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;type&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;System.Diagnostics.TextWriterTraceListener&lt;/SPAN&gt;"
&lt;SPAN style="COLOR: #0000ff"&gt;        &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;logFileTraceListener&lt;/SPAN&gt;"
&lt;SPAN style="COLOR: #0000ff"&gt;        &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;initializeData&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN class=style1&gt;AdminConsole&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;.log&lt;/SPAN&gt;"
&lt;SPAN style="COLOR: #0000ff"&gt;        &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;traceOutputOptions&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;DateTime&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
        &amp;lt;!--
&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;          Use a filter so that log file excludes low-level debugging messages
        &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
        &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;filter&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;type&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;System.Diagnostics.EventTypeFilter&lt;/SPAN&gt;"
&lt;SPAN style="COLOR: #0000ff"&gt;          &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;initializeData&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Information&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;sharedListeners&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
    &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;switches&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
      &amp;lt;!--&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Use this switch to output all log messages &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;allTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;All&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;!--&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Use this switch to output low-level debugging, informational,
        warning, and error messages &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;verboseTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Verbose&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;!--&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Use this switch to output informational, warning,
        and error messages &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;infoTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Info&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;!--&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Use this switch to output warning and error messages &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;warningTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Warning&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;!--&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Use this switch to output error messages &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;errorTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Error&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
      &amp;lt;!--&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Use this switch to output no tracing messages &lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;--&amp;gt;
      &amp;lt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;add&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;name&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;offTraceLevel&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #ff0000"&gt;value&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;=&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt;Off&lt;/SPAN&gt;"&lt;SPAN style="COLOR: #0000ff"&gt; /&amp;gt;
    &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;switches&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
  &amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;system.diagnostics&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;
&amp;lt;/&lt;/SPAN&gt;&lt;SPAN style="COLOR: #a31515"&gt;configuration&lt;/SPAN&gt;&lt;SPAN style="COLOR: #0000ff"&gt;&amp;gt;&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/CODE&gt;&lt;/DIV&gt;
&lt;P&gt;This produces a file named AdminConsole.log with the following content:&lt;/P&gt;
&lt;DIV class=consoleBlock&gt;&lt;PRE&gt;defaultTraceSource Information: 0 : AdminConsole.exe
    DateTime=2009-06-18T16:57:54.4488429Z
defaultTraceSource Warning: 0 : Unable to process work item -1 (The value must be greater than or equal to zero.
Parameter name: d).
    DateTime=2009-06-18T16:57:54.4798429Z
defaultTraceSource Information: 0 : Successfully completed processing.
    DateTime=2009-06-18T16:57:54.4818429Z
defaultTraceSource Information: 0 : Program complete.
    DateTime=2009-06-18T16:57:54.4828429Z&lt;/PRE&gt;&lt;/DIV&gt;
&lt;P&gt;Unfortunately the TextWriterTraceListener class appends the timestamp onto a separate line, but you can easily substitute a custom listener that formats results like the following, if necessary:&lt;/P&gt;&lt;PRE&gt;2009-06-18T17:17:43 Information: AdminConsole.exe
2009-06-18T17:17:43 Warning: Unable to process work item -1 (The value must be greater than or equal to zero.
Parameter name: d).
2009-06-18T17:17:43 Information: Successfully completed processing.
2009-06-18T17:17:43 Information: Program complete.
&lt;/PRE&gt;
&lt;P&gt;When I wrote the &lt;CODE&gt;Logger&lt;/CODE&gt; class a few years ago, I also wrote a &lt;CODE&gt;SimpleTraceListener&lt;/CODE&gt; class to do just this:&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;CODE&gt;&lt;PRE&gt;&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.Collections;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.Diagnostics;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.Globalization;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.IO;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.Runtime.InteropServices;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.Security.Permissions;

&lt;SPAN style="COLOR: #0000ff"&gt;namespace&lt;/SPAN&gt; Fabrikam.Demo.CoreServices.Logging
{
    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; 
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;    [&lt;SPAN style="COLOR: #2b91af"&gt;HostProtection&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #2b91af"&gt;SecurityAction&lt;/SPAN&gt;.LinkDemand, Synchronization = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;)]
    &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;class&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;SimpleTraceListener&lt;/SPAN&gt; : &lt;SPAN style="COLOR: #2b91af"&gt;TextWriterTraceListener
&lt;/SPAN&gt;    {
        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Initializes a new instance of the &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="SimpleTraceListener"/&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; class.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; SimpleTraceListener()
        {
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Initializes a new instance of the &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="SimpleTraceListener"/&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; class, using the specified stream as the recipient of the debugging
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; and tracing output.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="stream"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="Stream"/&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; that represents the
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; stream the &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="SimpleTraceListener"/&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; writes to.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; SimpleTraceListener(
            &lt;SPAN style="COLOR: #2b91af"&gt;Stream&lt;/SPAN&gt; stream)
            : &lt;SPAN style="COLOR: #0000ff"&gt;base&lt;/SPAN&gt;(stream, &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.Empty)
        {
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Initializes a new instance of the &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="SimpleTraceListener"/&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; class, using the specified writer as the recipient of the debugging
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; and tracing output.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="writer"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="TextWriter"/&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; that receives the
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; output from the &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="SimpleTraceListener"/&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; SimpleTraceListener(
            &lt;SPAN style="COLOR: #2b91af"&gt;TextWriter&lt;/SPAN&gt; writer)
            : &lt;SPAN style="COLOR: #0000ff"&gt;base&lt;/SPAN&gt;(writer, &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.Empty)
        {
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Initializes a new instance of the &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="SimpleTraceListener"/&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; class, using the specified file as the recipient of the debugging
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; and tracing output.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="fileName"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;The name of the file the
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="SimpleTraceListener"/&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; writes to.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; SimpleTraceListener(
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; fileName)
            : &lt;SPAN style="COLOR: #0000ff"&gt;base&lt;/SPAN&gt;(fileName)
        {
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Initializes a new instance of the &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="SimpleTraceListener"/&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; class with the specified name, using the specified stream as the
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; recipient of the debugging and tracing output.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="stream"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="Stream"/&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; that represents the
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; stream the &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="SimpleTraceListener"/&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; writes to.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="name"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;The name of the new instance.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; SimpleTraceListener(
            &lt;SPAN style="COLOR: #2b91af"&gt;Stream&lt;/SPAN&gt; stream,
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; name)
            : &lt;SPAN style="COLOR: #0000ff"&gt;base&lt;/SPAN&gt;(stream, name)
        {
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Initializes a new instance of the &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="SimpleTraceListener"/&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; class with the specified name, using the specified writer as the
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; recipient of the debugging and tracing output.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="writer"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="TextWriter"/&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; that receives the
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; output from the &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="SimpleTraceListener"/&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="name"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;The name of the new instance.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; SimpleTraceListener(
            &lt;SPAN style="COLOR: #2b91af"&gt;TextWriter&lt;/SPAN&gt; writer,
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; name)
            : &lt;SPAN style="COLOR: #0000ff"&gt;base&lt;/SPAN&gt;(writer, name)
        {
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Initializes a new instance of the &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="SimpleTraceListener"/&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; class with the specified name, using the specified file as the
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; recipient of the debugging and tracing output.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="fileName"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;The name of the file the
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;see cref="SimpleTraceListener"/&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; writes to.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="name"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;The name of the new instance.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; SimpleTraceListener(
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; fileName,
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; name)
            : &lt;SPAN style="COLOR: #0000ff"&gt;base&lt;/SPAN&gt;(fileName, name)
        {
        }

        &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;bool&lt;/SPAN&gt; IsEnabled(
            &lt;SPAN style="COLOR: #2b91af"&gt;TraceOptions&lt;/SPAN&gt; options)
        {
            &lt;SPAN style="COLOR: #0000ff"&gt;return&lt;/SPAN&gt; ((options &amp;amp; &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.TraceOutputOptions) != &lt;SPAN style="COLOR: #2b91af"&gt;TraceOptions&lt;/SPAN&gt;.None);
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Writes trace information, a message, and event information to the
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; listener specific output.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="eventCache"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A TraceEventCache object that contains the
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; current process ID, thread ID, and stack trace information.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="source"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A name used to identify the output, typically
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; the name of the application that generated the trace event.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="eventType"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;One of the TraceEventType values specifying
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; the type of event that has caused the trace.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="id"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A numeric identifier for the event.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="message"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A message to write.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        [&lt;SPAN style="COLOR: #2b91af"&gt;ComVisible&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;)]
        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;override&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; TraceEvent(
            &lt;SPAN style="COLOR: #2b91af"&gt;TraceEventCache&lt;/SPAN&gt; eventCache,
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; source,
            &lt;SPAN style="COLOR: #2b91af"&gt;TraceEventType&lt;/SPAN&gt; eventType,
            &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; id,
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; message)
        {
            &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ((&lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.Filter == &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;)
                || &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.Filter.ShouldTrace(
                    eventCache, source, eventType, id, message, &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;))
            {
                &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.WriteHeader(source, eventType, id, eventCache);
                &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.WriteLine(message);
                &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.WriteFooter(eventCache);
            }
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Writes trace information, a formatted array of objects and event
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; information to the listener specific output.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="eventCache"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A TraceEventCache object that contains the
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; current process ID, thread ID, and stack trace information.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="source"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A name used to identify the output, typically
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; the name of the application that generated the trace event.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="eventType"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;One of the TraceEventType values specifying
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; the type of event that has caused the trace.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="id"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A numeric identifier for the event.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="format"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A format string that contains zero or more
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; format items, which correspond to objects in the
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;paramref name="args"/&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; array.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="args"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;An object array containing zero or more objects
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; to format.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        [&lt;SPAN style="COLOR: #2b91af"&gt;ComVisible&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;)]
        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;override&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; TraceEvent(
            &lt;SPAN style="COLOR: #2b91af"&gt;TraceEventCache&lt;/SPAN&gt; eventCache,
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; source,
            &lt;SPAN style="COLOR: #2b91af"&gt;TraceEventType&lt;/SPAN&gt; eventType,
            &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; id,
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; format,
            &lt;SPAN style="COLOR: #0000ff"&gt;params&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;object&lt;/SPAN&gt;[] args)
        {
            &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; ((&lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.Filter == &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;)
                || &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.Filter.ShouldTrace(
                    eventCache, source, eventType, id, format, args, &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;))
            {
                &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.WriteHeader(source, eventType, id, eventCache);
                &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (args != &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;)
                {
                    &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.WriteLine(&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.Format(
                            &lt;SPAN style="COLOR: #2b91af"&gt;CultureInfo&lt;/SPAN&gt;.InvariantCulture, format, args));
                }
                &lt;SPAN style="COLOR: #0000ff"&gt;else
&lt;/SPAN&gt;                {
                    &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.WriteLine(format);
                }
                &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.WriteFooter(eventCache);
            }
        }

        &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; WriteFooter(
            &lt;SPAN style="COLOR: #2b91af"&gt;TraceEventCache&lt;/SPAN&gt; eventCache)
        {
            &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (eventCache == &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;)
            {
                &lt;SPAN style="COLOR: #0000ff"&gt;return&lt;/SPAN&gt;;
            }

            &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.IndentLevel++;
            &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.IsEnabled(&lt;SPAN style="COLOR: #2b91af"&gt;TraceOptions&lt;/SPAN&gt;.ProcessId))
            {
                &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.WriteLine(&lt;SPAN style="COLOR: #a31515"&gt;"ProcessId="&lt;/SPAN&gt; + eventCache.ProcessId);
            }
            &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.IsEnabled(&lt;SPAN style="COLOR: #2b91af"&gt;TraceOptions&lt;/SPAN&gt;.LogicalOperationStack))
            {
                &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.Write(&lt;SPAN style="COLOR: #a31515"&gt;"LogicalOperationStack="&lt;/SPAN&gt;);
                &lt;SPAN style="COLOR: #2b91af"&gt;Stack&lt;/SPAN&gt; logicalOperationStack = eventCache.LogicalOperationStack;
                &lt;SPAN style="COLOR: #0000ff"&gt;bool&lt;/SPAN&gt; flag = &lt;SPAN style="COLOR: #0000ff"&gt;true&lt;/SPAN&gt;;
                &lt;SPAN style="COLOR: #0000ff"&gt;foreach&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;object&lt;/SPAN&gt; obj2 &lt;SPAN style="COLOR: #0000ff"&gt;in&lt;/SPAN&gt; logicalOperationStack)
                {
                    &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (!flag)
                    {
                        &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.Write(&lt;SPAN style="COLOR: #a31515"&gt;", "&lt;/SPAN&gt;);
                    }
                    &lt;SPAN style="COLOR: #0000ff"&gt;else
&lt;/SPAN&gt;                    {
                        flag = &lt;SPAN style="COLOR: #0000ff"&gt;false&lt;/SPAN&gt;;
                    }
                    &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.Write(obj2.ToString());
                }
                &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.WriteLine(&lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.Empty);
            }
            &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.IsEnabled(&lt;SPAN style="COLOR: #2b91af"&gt;TraceOptions&lt;/SPAN&gt;.ThreadId))
            {
                &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.WriteLine(&lt;SPAN style="COLOR: #a31515"&gt;"ThreadId="&lt;/SPAN&gt; + eventCache.ThreadId);
            }
            &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.IsEnabled(&lt;SPAN style="COLOR: #2b91af"&gt;TraceOptions&lt;/SPAN&gt;.Timestamp))
            {
                &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.WriteLine(&lt;SPAN style="COLOR: #a31515"&gt;"Timestamp="&lt;/SPAN&gt; + eventCache.Timestamp);
            }
            &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.IsEnabled(&lt;SPAN style="COLOR: #2b91af"&gt;TraceOptions&lt;/SPAN&gt;.Callstack))
            {
                &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.WriteLine(&lt;SPAN style="COLOR: #a31515"&gt;"Callstack="&lt;/SPAN&gt; + eventCache.Callstack);
            }
            &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.IndentLevel--;
        }

        &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; WriteHeader(
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; source,
            &lt;SPAN style="COLOR: #2b91af"&gt;TraceEventType&lt;/SPAN&gt; eventType,
            &lt;SPAN style="COLOR: #0000ff"&gt;int&lt;/SPAN&gt; id,
            &lt;SPAN style="COLOR: #2b91af"&gt;TraceEventCache&lt;/SPAN&gt; eventCache)
        {
            &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (eventCache != &lt;SPAN style="COLOR: #0000ff"&gt;null&lt;/SPAN&gt;)
            {
                &lt;SPAN style="COLOR: #0000ff"&gt;if&lt;/SPAN&gt; (&lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.IsEnabled(&lt;SPAN style="COLOR: #2b91af"&gt;TraceOptions&lt;/SPAN&gt;.DateTime))
                {
                    &lt;SPAN style="COLOR: #2b91af"&gt;DateTime&lt;/SPAN&gt; localTime = eventCache.DateTime.ToLocalTime();
                    &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; formattedDate = localTime.ToString(
                        &lt;SPAN style="COLOR: #a31515"&gt;"s"&lt;/SPAN&gt;,
                        &lt;SPAN style="COLOR: #2b91af"&gt;CultureInfo&lt;/SPAN&gt;.InvariantCulture);

                    &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.Write(formattedDate);
                    &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.Write(&lt;SPAN style="COLOR: #a31515"&gt;" "&lt;/SPAN&gt;);
                }
            }

            &lt;SPAN style="COLOR: #0000ff"&gt;this&lt;/SPAN&gt;.Write(
                &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.Format(
                    &lt;SPAN style="COLOR: #2b91af"&gt;CultureInfo&lt;/SPAN&gt;.InvariantCulture,
                    &lt;SPAN style="COLOR: #a31515"&gt;"{0}: "&lt;/SPAN&gt;,
                    eventType.ToString()));
        }
    }
}
&lt;/PRE&gt;&lt;/CODE&gt;&lt;/DIV&gt;
&lt;P&gt;Depending on your specific needs, you could modify the &lt;CODE&gt;WriteHeader&lt;/CODE&gt; and &lt;CODE&gt;WriteFooter&lt;/CODE&gt; methods to output additional fields on the same line as the log message. (In my scenario, I only needed to support the &lt;A href="http://msdn.microsoft.com/en-us/library/a10k7w6c.aspx" mce_href="http://msdn.microsoft.com/en-us/library/a10k7w6c.aspx"&gt;TraceOptions.DateTime&lt;/A&gt;&amp;nbsp;option.)&lt;/P&gt;
&lt;P&gt;In my &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/06/18/configuring-logging-in-asp-net-applications-and-sharepoint.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/06/18/configuring-logging-in-asp-net-applications-and-sharepoint.aspx"&gt;next post&lt;/A&gt;, I discuss logging to the ASP.NET tracing feature.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9777215" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jjameson/archive/tags/Simplify/default.aspx">Simplify</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx">Core Development</category></item><item><title>A Simple, but Highly Effective Approach to Logging</title><link>http://blogs.msdn.com/jjameson/archive/2009/06/18/a-simple-but-highly-effective-approach-to-logging.aspx</link><pubDate>Fri, 19 Jun 2009 03:01:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9776928</guid><dc:creator>Jeremy Jameson</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/jjameson/comments/9776928.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jjameson/commentrss.aspx?PostID=9776928</wfw:commentRss><description>&lt;P&gt;A common question that frequently arises both with customers and fellow consultants is what do I recommend for logging? As experienced software developers, we know that there are going to be errors in our solution -- as well as other important events that we want to monitor -- and therefore we know we need a robust way of logging these.&lt;/P&gt;
&lt;P&gt;However, with numerous options available -- e.g. log4net, Enterprise Library, Common.Logging, SharePoint ULS, etc. -- it's no wonder this is frequently a "hot" topic.&lt;/P&gt;
&lt;P&gt;Several years ago, I created a simple, but highly effective approach to logging based on the (then) new System.Diagnostics features in the .NET Framework version 2.0.&lt;/P&gt;
&lt;P&gt;Before introducing my logging feature, it is first important to understand the goals (and non-goals) of the solution.&lt;/P&gt;
&lt;H5&gt;Goals and Non-Goals&lt;/H5&gt;
&lt;P&gt;The primary goals of the logging feature are:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Provide solution components a way of logging messages of various levels (e.g. errors, warnings, information) with minimal custom code.&lt;/LI&gt;
&lt;LI&gt;Ensure log messages can be enabled in all environments (e.g. DEV, TEST, and PROD); in other words, in both Debug and Release builds (unlike the &lt;CODE&gt;&lt;A href="http://msdn.microsoft.com/en-us/library/system.diagnostics.debug.writeline.aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.diagnostics.debug.writeline.aspx"&gt;Debug.WriteLine&lt;/A&gt;&lt;/CODE&gt; method, which relies on the DEBUG conditional compilation constant).&lt;/LI&gt;
&lt;LI&gt;Through configuration, enable log messages to be routed to various outputs such as a text file, the Windows Event Log, or &lt;A href="http://msdn.microsoft.com/en-us/library/bb386420.aspx" mce_href="http://msdn.microsoft.com/en-us/library/bb386420.aspx"&gt;ASP.NET tracing&lt;/A&gt;.&lt;/LI&gt;
&lt;LI&gt;Ensure that different levels of log messages can be filtered and potentially routed to different outputs; for example, log all messages to the console, but only log errors and warnings to a text file.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Non-goals of the logging feature include:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Providing the fastest possible logging implementation; rather the performance impact of logging should be insignificant when compared with the "real" work performed by the solution components.&lt;/LI&gt;
&lt;LI&gt;Changing logging configuration without reinitializing the solution; for example, to change the logging for an ASP.NET application, it is acceptable to restart the corresponding application pool.&lt;/LI&gt;
&lt;LI&gt;Filtering log messages based on subsystems (or feature areas) of the solution; for example, when logging is enabled for debug messages, then log messages from all components are output.&lt;/LI&gt;&lt;/UL&gt;
&lt;H5&gt;Introducing the Logger Class&lt;/H5&gt;
&lt;P&gt;With the custom &lt;CODE&gt;Logger&lt;/CODE&gt; class, logging a debug message is simply a matter of calling a static method, specifying nothing more than a string containing the message :&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;CODE&gt;&lt;PRE&gt;    &lt;SPAN style="COLOR: #2b91af"&gt;Logger&lt;/SPAN&gt;.LogDebug(&lt;SPAN style="COLOR: #a31515"&gt;"Successfully loaded search results into DataSet."&lt;/SPAN&gt;);&lt;/PRE&gt;&lt;/CODE&gt;&lt;/DIV&gt;
&lt;P&gt;This example shows how the &lt;CODE&gt;Logger&lt;/CODE&gt; class achieves the primary design goal. Note that there is no need to explicitly create objects within each class -- or create additional classes within an assembly -- for logging purposes.&lt;/P&gt;
&lt;P&gt;Also note that the &lt;CODE&gt;Logger&lt;/CODE&gt; class provides additional overloads to easily format log messages:&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;CODE&gt;&lt;PRE&gt;    &lt;SPAN style="COLOR: #2b91af"&gt;Logger&lt;/SPAN&gt;.LogDebug(
        &lt;SPAN style="COLOR: #2b91af"&gt;CultureInfo&lt;/SPAN&gt;.InvariantCulture,
        &lt;SPAN style="COLOR: #a31515"&gt;"Successfully loaded embedded resource ({0})"
&lt;/SPAN&gt;            + &lt;SPAN style="COLOR: #a31515"&gt;" ({1:n0} bytes) from assembly ({2})."&lt;/SPAN&gt;,
        resourceName,
        resourceContent.Length,
        resourceAssembly.FullName);&lt;/PRE&gt;&lt;/CODE&gt;&lt;/DIV&gt;
&lt;P&gt;Note that the &lt;CODE&gt;Logger.LogDebug&lt;/CODE&gt; method is simply a convenient alternative to the &lt;CODE&gt;Logger.Log&lt;/CODE&gt; method:&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;CODE&gt;&lt;PRE&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Logs an event to the trace listeners using the specified
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; event type and message.
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="eventType"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;One of the System.Diagnostics.TraceEventType
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; values that specifies the type of event being logged.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="message"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;The message to log.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; Log(
        &lt;SPAN style="COLOR: #2b91af"&gt;TraceEventType&lt;/SPAN&gt; eventType,
        &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; message)&lt;/PRE&gt;&lt;/CODE&gt;&lt;/DIV&gt;
&lt;P&gt;Other methods such as &lt;CODE&gt;LogInfo&lt;/CODE&gt; and &lt;CODE&gt;LogError&lt;/CODE&gt; provide similar overloads for convenience.&lt;/P&gt;
&lt;P&gt;The simplicity of the &lt;CODE&gt;Logger &lt;/CODE&gt;class is made possible by the improved tracing functionality introduced in the .NET Framework version 2.0. Specifically, the &lt;CODE&gt;Logger &lt;/CODE&gt;class is simply a "&lt;A href="http://en.wikipedia.org/wiki/Mr_Creosote" mce_href="http://en.wikipedia.org/wiki/Mr_Creosote"&gt;wafer-thin&lt;/A&gt;" wrapper around the &lt;A href="http://msdn.microsoft.com/en-us/library/system.diagnostics.tracesource(VS.80).aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.diagnostics.tracesource(VS.80).aspx"&gt;System.Diagnostics.TraceSource&lt;/A&gt; class.&lt;/P&gt;
&lt;P&gt;The &lt;CODE&gt;Logger &lt;/CODE&gt;class declares a singleton &lt;CODE&gt;TraceSource&lt;/CODE&gt; that is used to log all messages:&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;CODE&gt;&lt;PRE&gt;    &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;TraceSource&lt;/SPAN&gt; defaultTraceSource =
        &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;TraceSource&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #a31515"&gt;"defaultTraceSource"&lt;/SPAN&gt;);
&lt;/PRE&gt;&lt;/CODE&gt;&lt;/DIV&gt;
&lt;P&gt;Various listeners can then be configured to output log messages. Each type of listener derives from &lt;A href="http://msdn.microsoft.com/en-us/library/system.diagnostics.tracelistener(VS.80).aspx" mce_href="http://msdn.microsoft.com/en-us/library/system.diagnostics.tracelistener(VS.80).aspx"&gt;TraceListener&lt;/A&gt;.&lt;/P&gt;
&lt;P&gt;Note that the .NET Framework includes listeners for logging to a file, the Windows Event Log, as well as ASP.NET tracing. Consequently, with just a little bit of custom code (i.e. the &lt;CODE&gt;Logger&lt;/CODE&gt; class) combined with all the "goodness" baked into the core .NET Framework, we have a logging feature that meets all of the established goals.&lt;/P&gt;
&lt;P&gt;In my &lt;A href="http://blogs.msdn.com/jjameson/archive/2009/06/18/configuring-logging-in-a-console-application.aspx" mce_href="http://blogs.msdn.com/jjameson/archive/2009/06/18/configuring-logging-in-a-console-application.aspx"&gt;next post&lt;/A&gt;, I introduce how to configure logging (starting out with a console application).&lt;/P&gt;
&lt;P&gt;Here is the complete source for the &lt;CODE&gt;Logger&lt;/CODE&gt; class:&lt;/P&gt;
&lt;DIV class=codeBlock&gt;&lt;CODE&gt;&lt;PRE&gt;&lt;SPAN style="COLOR: #0000ff"&gt;#define&lt;/SPAN&gt; TRACE

&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.Diagnostics;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.Globalization;
&lt;SPAN style="COLOR: #0000ff"&gt;using&lt;/SPAN&gt; System.Text;

&lt;SPAN style="COLOR: #0000ff"&gt;namespace&lt;/SPAN&gt; Fabrikam.Demo.CoreServices.Logging
{
    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Exposes static methods for logging various events (e.g. debug,
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; informational, warning, etc.). This class cannot be inherited.
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;remarks&amp;gt;
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; All methods of the &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;b&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;Logger&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/b&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; class are static
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; and can therefore be called without creating an instance of the class.
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/remarks&amp;gt;
&lt;/SPAN&gt;    &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;sealed&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;class&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;Logger
&lt;/SPAN&gt;    {
        &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;TraceSource&lt;/SPAN&gt; defaultTraceSource =
            &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;TraceSource&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #a31515"&gt;"defaultTraceSource"&lt;/SPAN&gt;);

        &lt;SPAN style="COLOR: #0000ff"&gt;private&lt;/SPAN&gt; Logger() { } &lt;SPAN style="COLOR: #008000"&gt;// all members are static

&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Flushes all the trace listeners in the trace listener collection.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; Flush()
        {
            defaultTraceSource.Flush();
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Logs an event to the trace listeners using the specified
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; event type and message.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="eventType"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;One of the System.Diagnostics.TraceEventType
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; values that specifies the type of event being logged.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="message"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;The message to log.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; Log(
            &lt;SPAN style="COLOR: #2b91af"&gt;TraceEventType&lt;/SPAN&gt; eventType,
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; message)
        {
&lt;SPAN style="COLOR: #0000ff"&gt;#if&lt;/SPAN&gt; DEBUG
            &lt;SPAN style="COLOR: #008000"&gt;// Some debug listeners (e.g. DbgView.exe) don't buffer output, so
&lt;/SPAN&gt;            &lt;SPAN style="COLOR: #008000"&gt;// Debug.Write() is effectively the same as Debug.WriteLine().
&lt;/SPAN&gt;            &lt;SPAN style="COLOR: #008000"&gt;// For optimal appearance in these listeners, format the output
&lt;/SPAN&gt;            &lt;SPAN style="COLOR: #008000"&gt;// for a single call to Debug.WriteLine().
&lt;/SPAN&gt;            &lt;SPAN style="COLOR: #2b91af"&gt;StringBuilder&lt;/SPAN&gt; sb = &lt;SPAN style="COLOR: #0000ff"&gt;new&lt;/SPAN&gt; &lt;SPAN style="COLOR: #2b91af"&gt;StringBuilder&lt;/SPAN&gt;();

            sb.Append(eventType.ToString());
            sb.Append(&lt;SPAN style="COLOR: #a31515"&gt;": "&lt;/SPAN&gt;);
            sb.Append(message);

            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; formattedMessage = sb.ToString();
            &lt;SPAN style="COLOR: #2b91af"&gt;Debug&lt;/SPAN&gt;.WriteLine(formattedMessage);
&lt;SPAN style="COLOR: #0000ff"&gt;#endif

&lt;/SPAN&gt;            defaultTraceSource.TraceEvent(eventType, 0, message);
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Logs a debug event to the trace listeners using the specified
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; format string and arguments.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="provider"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;An System.IFormatProvider that supplies
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; culture-specific formatting information.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="format"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A composite format string.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="args"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;An System.Object array containing zero or more
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; objects to format.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; LogDebug(
            &lt;SPAN style="COLOR: #2b91af"&gt;IFormatProvider&lt;/SPAN&gt; provider,
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; format,
            &lt;SPAN style="COLOR: #0000ff"&gt;params&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;object&lt;/SPAN&gt;[] args)
        {
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; message = &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.Format(
                provider, format, args);

            LogDebug(message);
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Logs a debug event to the trace listeners.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="message"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;The message to log.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; LogDebug(
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; message)
        {
            Log(&lt;SPAN style="COLOR: #2b91af"&gt;TraceEventType&lt;/SPAN&gt;.Verbose, message);
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Logs a critical event to the trace listeners using the specified
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; format string and arguments.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="provider"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;An System.IFormatProvider that supplies
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; culture-specific formatting information.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="format"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A composite format string.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="args"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;An System.Object array containing zero or more
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; objects to format.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; LogCritical(
            &lt;SPAN style="COLOR: #2b91af"&gt;IFormatProvider&lt;/SPAN&gt; provider,
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; format,
            &lt;SPAN style="COLOR: #0000ff"&gt;params&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;object&lt;/SPAN&gt;[] args)
        {
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; message = &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.Format(
                provider, format, args);

            LogCritical(message);
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Logs a critical event to the trace listeners.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="message"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;The message to log.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; LogCritical(
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; message)
        {
            Log(&lt;SPAN style="COLOR: #2b91af"&gt;TraceEventType&lt;/SPAN&gt;.Critical, message);
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Logs an error event to the trace listeners using the specified
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; format string and arguments.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="provider"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;An System.IFormatProvider that supplies
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; culture-specific formatting information.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="format"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A composite format string.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="args"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;An System.Object array containing zero or more
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; objects to format.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; LogError(
            &lt;SPAN style="COLOR: #2b91af"&gt;IFormatProvider&lt;/SPAN&gt; provider,
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; format,
            &lt;SPAN style="COLOR: #0000ff"&gt;params&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;object&lt;/SPAN&gt;[] args)
        {
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; message = &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.Format(
                provider, format, args);

            LogError(message);
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Logs an error event to the trace listeners.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="message"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;The message to log.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; LogError(
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; message)
        {
            Log(&lt;SPAN style="COLOR: #2b91af"&gt;TraceEventType&lt;/SPAN&gt;.Error, message);
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Logs an informational event to the trace listeners using the specified
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; format string and arguments.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="provider"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;An System.IFormatProvider that supplies
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; culture-specific formatting information.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="format"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A composite format string.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="args"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;An System.Object array containing zero or more
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; objects to format.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; LogInfo(
            &lt;SPAN style="COLOR: #2b91af"&gt;IFormatProvider&lt;/SPAN&gt; provider,
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; format,
            &lt;SPAN style="COLOR: #0000ff"&gt;params&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;object&lt;/SPAN&gt;[] args)
        {
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; message = &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.Format(
                provider, format, args);

            LogInfo(message);
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Logs an informational event to the trace listeners.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="message"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;The message to log.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; LogInfo(
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; message)
        {
            Log(&lt;SPAN style="COLOR: #2b91af"&gt;TraceEventType&lt;/SPAN&gt;.Information, message);
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Logs a warning event to the trace listeners using the specified
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; format string and arguments.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="provider"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;An System.IFormatProvider that supplies
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; culture-specific formatting information.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="format"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;A composite format string.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="args"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;An System.Object array containing zero or more
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; objects to format.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; LogWarning(
            &lt;SPAN style="COLOR: #2b91af"&gt;IFormatProvider&lt;/SPAN&gt; provider,
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; format,
            &lt;SPAN style="COLOR: #0000ff"&gt;params&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;object&lt;/SPAN&gt;[] args)
        {
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; message = &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt;.Format(
                provider, format, args);

            LogWarning(message);
        }

        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; Logs a warning event to the trace listeners.
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/summary&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #808080"&gt;///&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;param name="message"&amp;gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: #008000"&gt;The message to log.&lt;/SPAN&gt;&lt;SPAN style="COLOR: #808080"&gt;&amp;lt;/param&amp;gt;
&lt;/SPAN&gt;        &lt;SPAN style="COLOR: #0000ff"&gt;public&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;static&lt;/SPAN&gt; &lt;SPAN style="COLOR: #0000ff"&gt;void&lt;/SPAN&gt; LogWarning(
            &lt;SPAN style="COLOR: #0000ff"&gt;string&lt;/SPAN&gt; message)
        {
            Log(&lt;SPAN style="COLOR: #2b91af"&gt;TraceEventType&lt;/SPAN&gt;.Warning, message);
        }
    }
}
&lt;/PRE&gt;&lt;/CODE&gt;&lt;/DIV&gt;
&lt;P&gt;Note that the Logger.cs file actually includes &lt;CODE&gt;#define TRACE&lt;/CODE&gt; at the top of the file. This is because I originally wrote this class with an old version of Visual Studio (which did not define this compilation constant by default when creating new projects). Visual Studio 2008 projects include this in the project options by default (for both Debug and Release configurations), so this is superfluous.&lt;/P&gt;
&lt;P&gt;As you can see, there's really not much to this class (which hopefully means there isn't much that can go wrong with it). Most, if not all, of it should be very straightforward. I'll explain the importance of the &lt;CODE&gt;Logger.Flush&lt;/CODE&gt; method in my next post.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9776928" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jjameson/archive/tags/Simplify/default.aspx">Simplify</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/MOSS+2007/default.aspx">MOSS 2007</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx">Core Development</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/WSS+v3/default.aspx">WSS v3</category></item><item><title>Environment Naming Conventions</title><link>http://blogs.msdn.com/jjameson/archive/2009/06/09/environment-naming-conventions.aspx</link><pubDate>Wed, 10 Jun 2009 02:42:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9718725</guid><dc:creator>Jeremy Jameson</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/jjameson/comments/9718725.aspx</comments><wfw:commentRss>http://blogs.msdn.com/jjameson/commentrss.aspx?PostID=9718725</wfw:commentRss><description>&lt;P&gt;One of the challenges I see in organizations that I work with is the lack of naming conventions for various environments -- or sometimes naming conventions that provide little or no value.&lt;/P&gt;
&lt;P&gt;For about the last ten years, I've been a strong proponent of a simple "-suffix" naming convention that is not only very easy to learn (and remember!) but also makes things incredibly obvious to all team members and stakeholders on a project.&lt;/P&gt;
&lt;P&gt;Most enterprise IT organizations typically have a naming convention for servers that includes things like the Active Directory domain the server is a member of, the role of the server, and usually some unique identifier to distinguish multiple servers in a farm. Other "ingredients" such as the datacenter the server is physically located in may also be included.&lt;/P&gt;
&lt;P&gt;For example, my favorite fictitious manufacturing company, Fabrikam Technologies, has Production servers named:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;FAB-DC-01 (the first domain controller for the FABRIKAM domain),&lt;/LI&gt;
&lt;LI&gt;FAB-DC-02,&lt;/LI&gt;
&lt;LI&gt;FAB-WEB-01 (the first Web server in a farm),&lt;/LI&gt;
&lt;LI&gt;FAB-WEB-02,&lt;/LI&gt;
&lt;LI&gt;FAB-SQL-01A (the first node in a SQL Server cluster, for which the cluster is named FAB-SQL-01),&lt;/LI&gt;
&lt;LI&gt;FAB-SQL-01B,&lt;/LI&gt;
&lt;LI&gt;etc.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;This is a great start. As you can see from these examples, it's pretty easy to tell what the role of each server is.&lt;/P&gt;
&lt;P&gt;However, in any organization of reasonable size, we certainly need more than just the Production environment (PROD). At a minimum, I recommend using a Test environment (TEST) and a Development environment (DEV). Note that this is in addition to individual developer environments -- which I typically refer to as "local" evironments (LOCAL). Depending on how much parallel development is planned -- and the corresponding release schedule -- you might also need a Maintenance environment (MAINT). However, many organizations can function effectively with just the DEV-TEST-PROD triad.&lt;/P&gt;
&lt;P&gt;So this begs the question, what names should we use for DEV and TEST?&lt;/P&gt;
&lt;P&gt;Here is what I recommend:&lt;/P&gt;
&lt;P&gt;Monikers in the Development environment utilize a “-dev” suffix. For example, the Web server in DEV corresponding to the FAB-WEB-01 server in PROD is named FAB-WEB-01-DEV. Likewise, the SQL Server in the Development environment is named FAB-SQL-01A-DEV. Note that typically Development environments do not have a cluster, but I still recommend following the same naming convention and even adding a DNS entry for the DEV "cluster" name (e.g. FAB-SQL-01-DEV). Test environments often do have a SQL Server cluster configuration (which is a great place to validate your failover configuration and load testing).&lt;/P&gt;
&lt;P&gt;Host headers in the Development environment also follow the “-dev” naming convention. For example, if the internal name of the Fabrikam Web site in Production is &lt;A href="http://fabrikam/" mce_href="http://fabrikam"&gt;http://fabrikam&lt;/A&gt;, then &lt;A href="http://fabrikam-dev/" mce_href="http://fabrikam-dev"&gt;http://fabrikam-dev&lt;/A&gt; is the corresponding URL used in the Development environment.&lt;/P&gt;
&lt;P&gt;In order to distinguish sites on the local development VMs, the “-local” suffix is used. For example, &lt;A href="http://fabrikam-local/" mce_href="http://fabrikam-local"&gt;http://fabrikam-local&lt;/A&gt; is the URL on an individual developer’s VM corresponding to &lt;A href="http://fabrikam/" mce_href="http://fabrikam"&gt;http://fabrikam&lt;/A&gt; in Production. The %WINDIR%\System32\Drivers\etc\hosts file is then used to associate these URLs with the loopback address (127.0.0.1). [Be sure you are aware of the workaround in &lt;A href="http://support.microsoft.com/kb/896861" mce_href="http://support.microsoft.com/kb/896861"&gt;KB 896861&lt;/A&gt; when using the loopback address.]&lt;/P&gt;
&lt;P&gt;Similarly, monikers and host headers in the Test environment utilize a “-test” suffix (e.g. FAB-WEB-01-TEST, FAB-SQL-01A-TEST, and &lt;A href="http://fabrikam-test/" mce_href="http://fabrikam-test"&gt;http://fabrikam-test&lt;/A&gt;).&lt;/P&gt;
&lt;P&gt;Also note that organizations typically create separate service accounts within Active Directory for the Development, Test, and Production environments (and if you are not currently doing this, I strongly recommend it). For example, suppose &lt;STRONG&gt;FABRIKAM\svc-web&lt;/STRONG&gt; is the service account for the application pool running &lt;A href="http://fabrikam/" mce_href="http://fabrikam"&gt;http://fabrikam&lt;/A&gt; in Production. Then we would expect the Web site in DEV to be running as &lt;STRONG&gt;FABRIKAM\svc-web-dev&lt;/STRONG&gt; and the site in TEST to be running as &lt;STRONG&gt;FABRIKAM\svc-web-test&lt;/STRONG&gt;.&lt;/P&gt;
&lt;P&gt;This ensures that only the minimal number of people need to know the passwords for a particular environment. For example, either the whole Development team -- or just a small subset of team leads -- needs to know the password for &lt;STRONG&gt;FABRIKAM\svc-web-dev&lt;/STRONG&gt;, but they certainly don't know the password for &lt;STRONG&gt;FABRIKAM\svc-web-test&lt;/STRONG&gt; (since that environment is managed by the Test team). Likewise, the Test team had better not know the password for the service account in Production (since -- at least hopefully -- that environment is owned by a separate Release Management team).&lt;/P&gt;
&lt;P&gt;It is also important to point out how this naming convention is applied to fully qualified domain names (FQDNs). For example, suppose the external address of &lt;A href="http://fabrikam/" mce_href="http://fabrikam"&gt;http://fabrikam&lt;/A&gt; is &lt;A href="http://www.fabrikam.com/" mce_href="http://www.fabrikam.com"&gt;http://www.fabrikam.com&lt;/A&gt;. What then should we use for the corresponding FQDN in DEV, or should we even configure an FQDN for DEV? The answer to that latter question is a resounding "Yes!" and the answer to the former is &lt;A href="http://www-dev.fabrikam.com/" mce_href="http://www-dev.fabrikam.com"&gt;http://www-dev.fabrikam.com&lt;/A&gt;. Note that we almost certainly won't to expose DEV on the Internet -- although we may choose to expose TEST (&lt;A href="http://www-test.fabrikam.com/" mce_href="http://www-test.fabrikam.com"&gt; http://www-test.fabrikam.com&lt;/A&gt;) &lt;/P&gt;
&lt;P&gt;The primary reason I recommend using these FQDNs (aside from the fact that we are following the simple "-suffix" naming convention) is that browsers behave differently between intranet names (e.g. &lt;A href="http://fabrikam-dev/" mce_href="http://fabrikam-dev"&gt;http://fabrikam-dev&lt;/A&gt;) and FQDNs (e.g. &lt;A href="http://www-dev.fabrikam.com/" mce_href="http://www-dev.fabrikam.com"&gt;http://www-dev.fabrikam.com&lt;/A&gt;). In other words, when you are trying to simulate a problem on the external site, you should ensure that you are simulating the same security "zone" in DEV, or even in your local environment (e.g. &lt;A href="http://www-local.fabrikam.com/" mce_href="http://www-local.fabrikam.com"&gt;http://www-local.fabrikam.com&lt;/A&gt;).&lt;/P&gt;
&lt;P&gt;Lastly, I want to mention documentation. Whenever I sit down to write an Installation Guide -- or similar documentation -- I typically only specify the values for the Production environment, even though I fully expect the document to also be used to install and configure the Test and Development environments. I simply include a brief section at the beginning of the document describing the naming convention and that it is the responsibility of the developer or tester to modify the server names, host headers, and service accounts appropriately as he or she is following along when configuring DEV or TEST.&lt;/P&gt;
&lt;P&gt;Since we typically have "infrastructure models" (i.e. Visio diagrams showing the physical architecture of DEV, TEST, and PROD), identifying servers and host headers in various environments is really straightforward.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9718725" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/jjameson/archive/tags/My+System/default.aspx">My System</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Simplify/default.aspx">Simplify</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/MOSS+2007/default.aspx">MOSS 2007</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Core+Development/default.aspx">Core Development</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/WSS+v3/default.aspx">WSS v3</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/SQL+Server/default.aspx">SQL Server</category><category domain="http://blogs.msdn.com/jjameson/archive/tags/Infrastructure/default.aspx">Infrastructure</category></item></channel></rss>