Monday, June 7, 2010

Windbg Ignoring Sympath when called programatically

Working with mdbglib this weekend my call to .sympath was registering but then none of the symbol files could be found.  This post will show how to resolve this issue and the process I followed to solve it.

Environment Windows Server R2 64 bit.  The app is compiled for x86 and running as a 32 bit app.

  1. lm e
    This listed modules which had errors.
  2. reload -f
    Force a reload of all modules.  Noticed none of them were loading from my path.
  3. Hooked up SysInternals Process Monitor filtered to just my process name and just disk activity.  cleared the output right before doing reload -f
    NOticed it was attempting to load modules from the same directory I was running from.
  4. restarted the application
  5. !sym noisy
    To noisy load symbols.
  6. .reload

    DBGHELP: SymSrv load failure: symsrv.dll
    DBGHELP: wntdll.pdb - file not found
    *** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\SysWOW64\ntdll.dll - 
    DBGHELP: ntdll - export symbols
    DBGHELP: wuser32.pdb - file not found
    *** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Windows\syswow64\USER32.dll - 
    DBGHELP: USER32 - export symbols
    DBGHELP: System.Windows.Forms.pdb - file not found
    *** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v2.0.50727_32\System.Windows.Forms\fedf1ba58dced4f0b3f8c457648ceed9\System.Windows.Forms.ni.dll
    *** ERROR: Module load completed but symbols could not be loaded for C:\Windows\assembly\NativeImages_v2.0.50727_32\System.Windows.Forms\fedf1ba58dced4f0b3f8c457648ceed9\System.Windows.Forms.ni.dll
    DBGHELP: System_Windows_Forms_ni - no symbols loaded

  7. Copied symsrv.dll into my local directory even though it is already in the app path.
  8. Restarted, !sym noisy, .reload
    same results
  9. Filter Process monitor where the path ends in symsrv.dll
    Noticed the process is trying to load symsrv.dll from C:\Windows\SysWOW64\
  10. Copied symsrv.dll to C:\Windows\SysWOW64
    HACK!
  11. restarted, !sym noisy, .reload
    success!
  12. .chain
    Shows dbghelp.dll is loaded from c:\Windows\system32\dbghelp.dll
    MSDN writes symsrv must be installed in the same directory as the copy of dbghelp.dll being loaded.
  13. .extpath C:\Program Files (x86)\Debugging Tools for Windows (x86)\
    sets dbgeng's extension search path to where symsrv.dll is.
  14. .chain
    dbghelp.dll is still loaded from the system32 directory.
  15. Prior to running the debugger I set the environmental variable _NT_DEBUGGER_EXTENSION_PATH to C:\Program Files (x86)\Debugging Tools for Windows (x86)\
  16. Restart, .chain
    dbghelp is loaded from the correct directory! but symsrv.dll is still broken :(
    Looking at the stack in Process monitor shows dbgeng.dll is being loaded from C:\Windows\SysWOW64\dbgeng.dll which calls dbghelp.dll in the same directory.
    Changing process monitor to filter for requests ending in dbgeng.dll shows when the program runs it is looking in the executing applications directory for the dll, not finding it, and then loading it from C:\Windows\SysWOW64\dbgeng.dll
  17. Head over to pinvoke.net to grab the loadlibrary signature and put it in my application.

    [DllImport("kernel32", SetLastError = true)]
    static extern IntPtr LoadLibrary(string lpFileName);

  18. Call LoadLibrary from C# prior to loading my debugger and now the correct dll is bing loaded, but the debugging commands don't return any values :(
  19. Reading the LoadLibrary documentation and then the dll search order documentation I think calling SetDllDirectory may do what I want.
  20. Back to pinvoke.net to grab this signature
    [DllImport("kernel32.dll", SetLastError=true)]
    static extern bool SetDllDirectory(string lpPathName); 
  21. Call SetDllDirectory prior to loading up the debugger and everything now works as expected!

Here is the code:

internal static class UnsafeNativeMethods
{
    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern bool SetDllDirectory(string lpPathName);
}



public static class Utility
{
    public static void ProvideWindbgInstallationDirectory(string path)
    {
        if (Directory.Exists(path) == false)
        {
            throw new DirectoryNotFoundException(path);
        }
        #warning add a check that the files we want exist.  maybe even that they are the correct version?
        bool setPath = UnsafeNativeMethods.SetDllDirectory(path);
        if (setPath == false)
        {
            int error = Marshal.GetLastWin32Error();
            throw new InvalidOperationException("Setting the installation directory failed with error code: " + error.ToString());

        }
    }
}



Monday, March 29, 2010

Using WindDbg and Sosex to Identify an ASP.NET Deadlock

This post will show how to use create an ASP.NET deadlock and then then use WinDbg and sosex to identify it the idea is to practice this before needing it when debugging a production server :)


The environment for my test is

  1. Create a new web application and put this in the code behind for Default.aspx:
    public partial class _Default : Page
    {
        /// <summary>
        /// Locks on page load.
        /// </summary>
        protected void Page_Load(object sender, EventArgs e)
        {
            object lockA = new object();

            object lockB = new object();

            ThreadStart firstJob = new ThreadStart(() => this.DualLockingCall(lockA, lockB));
            Thread firstThread = new Thread(firstJob);
            firstThread.Name = "firstThread";
            firstThread.Start();

            ThreadStart secondJob = new ThreadStart(() => this.DualLockingCall(lockB, lockA));
            Thread secondThread = new Thread(secondJob);
            secondThread.Name = "secondThread";
            secondThread.Start();

            Thread.Sleep(Timeout.Infinite);
        }

        /// <summary>
        /// lock on a then lock on b.
        /// </summary>
        /// <param name="onThis">The first instance to lock on.</param>
        /// <param name="onThat">The second instance to lock on.</param>
        private void DualLockingCall(object onThis, object onThat)
        {
            lock (onThis)
            {
                lock (onThat)
                {
                    Thread.Sleep(TimeSpan.FromSeconds(5));
                }
            }
        }
    }
  2. Navigate to the url like localhost/projectName/Default.aspx
  3. Open a command prompt and navigate to the debugging tools for windows directory.
  4. Run this command adplus -pn w3wp.exe -o c:\ -hang
    1. The hang command takes a memory dump immediately.  It doesn't wait for a hang.
  5. Note the output directory.  It should be the last line adplus printed out.
  6. Run windbg and press ctrl+d to open a memory dump.  Navigate to the dump adplus just created.
  7. type .loadby sos mscorwks - This will load the sos.dll from the same directory mscorwks was loaded from.
  8. type .load pathToSosex\sosex.dll
  9. type !dlk
  10. On my machine I get this output:
    *** WARNING: Unable to verify checksum for LockItUp.DLL
    *** ERROR: Module load completed but symbols could not be loaded for LockItUp.DLL
    Deadlock detected:
    CLR thread 8 holds sync block 0000000002583228 OBJ:00000001bf1f2be0[System.Object]
                 waits sync block 00000000025831e0 OBJ:00000001bf1f2bf8[System.Object]
    CLR thread 9 holds sync block 00000000025831e0 OBJ:00000001bf1f2bf8[System.Object]
                 waits sync block 0000000002583228 OBJ:00000001bf1f2be0[System.Object]
    CLR Thread 8 is waiting at LockItUp._Default.DualLockingCall(System.Object, System.Object)(+0x25 IL)(+0x74 Native)
    CLR Thread 9 is waiting at LockItUp._Default.DualLockingCall(System.Object, System.Object)(+0x25 IL)(+0x74 Native)

    1 deadlock detected.
Easy cheesy in this simulated test eh?



Monday, March 22, 2010

A Test of My Mettle

I attended my first Toastmaster's meeting last Wednesday and experienced special guest Ed Hearn deliver an inspirational thought provoking speech entitled: "The Courage to Try."

Mr. Hearn gave examples of individuals achieving seemingly impossible goals such as Wilma Rudolph winning three Olympic Gold medals despite having a severe physical disability as a child.  In each example the actors overcame daunting obstacles to realize fantastic goals.

During the speech I was thinking about people's opportunities in life, and how I did not have to struggle to complete High School, College, or get a professional job.  I've taken advantage of opportunities which were nearly given to me, but I haven't made my own opportunities.  Mr. Hearn's speech combined with some of my other experiences have made me realize the goals I attempt in life are low risk or low effort. When I take on large (1,000+ hours) personal projects I give up on the projects after investing a small (10-700 hours) amount of effort into them compared to the amount of effort required for completion.  I'm assuming I give up because I don't see results and overvalue the opportunity cost.  IE.  I think "Hmmmmmm...... I've spent 50 hours on this which I could have spent completing items x,y, and z on my todo list instead.  It may take another 500 hours to achieve my goal, or I may not even be able to achieve my goal," and sack the project.

I am not sure if this new thinking will bear fruit.  Unless I can talk myself into believing there is significant value in the act of trying I'm not sure I can justify the cost of the attempt.  Maybe because I plan for the worst and hope for the best.  Under this mentality I assume the 1000+ hours invested will not achieve the stated objective.

Monday, March 15, 2010

Viewing ASP.NET Adaptive Rendering

I remembered when ASP.NET launched hearing about adaptive rendering.  Using ASP.NET I did not notice different renderings.  This post shows how one can observe ASP.NET adaptive renderings using fiddler.

The software used for this post is:
  • Visual Studio 2008 SP1
  • Windows Server 2008 R2 Standard
  • Fiddler v2.2.8.6 64-bit
  • IE 8.0
  1. Using Visual Studio create a new ASP.NET Web Application
  2. Modify Default.aspx.cs as follows:
    public partial class _Default : Page


    {
        /// <summary>
        /// Ignores this pages children and demonstrates different HtmlWriters based on
        /// different request strings.
        /// </summary>
        /// <param name="writer">An HtmlWriter passed by ASP.NET.</param>
        protected override void Render(HtmlTextWriter writer)
        {
            writer.Write(HttpContext.Current.Request.Browser.TagWriter.ToString());

            writer.AddStyleAttribute(HtmlTextWriterStyle.Color, "Red");
            writer.RenderBeginTag(HtmlTextWriterTag.P);
            writer.Write("Red text");
            writer.RenderEndTag();
        }
    }
  3. Run the project and note the port it runs on.  In my case the url is http://localhost:56449.  Running in IE 8 I see:
    System.Web.UI.HtmlTextWriter


    Red text
  4. In Fiddler enter Request Builder, build and execute the following request:
    Get http://ipv4.fiddler:YOURPORT HTTP/1.1
    User-Agent: Mozilla(compatible;MSIE 3.0;)
     Host: ipv4.fiddler:YOURPORT
  5. In the Web Sessions click the session resulting from your request
  6. Select the Inspectors tab and select TextView.  On my machine I see:
    System.Web.UI.Html32TextWriter<p><font color="Red">Red text</font></p>
    Since we specified our user-agent as MSIE 3.0 ASP.NET is rendering the style color using the font tag.
  7. Go back to Fiddler Request Builder, build and execute the following request:
    Get http://ipv4.fiddler:YOURPORT HTTP/1.1
    User-Agent: Mozilla(compatible;MSIE 4.0;)
     Host: ipv4.fiddler:YOURPORT
  8. In the Web Sessions click the session resulting from your request
  9. Select the Inspectors tab and select TextView. On my machine I see:
    System.Web.UI.HtmlTextWriter<p style="color:Red;">Red text</p>
  10. There are a couple of differences between the two responses:
    1. HtmlTextWriter was used whereas in the previous request it was an Html32TextWriter.
    2. ASP.NET renedered the style color using CSS instead of the font tag.

To undestand the mechanics making this happen 4 Guys From Rolla have an article describing the details.

Above I used ipv4.fiddler instead of localhost to enable seeing traffic sent to localhost as described in Fiddler's help.

Monday, March 1, 2010

Equal but different JavaScript style

Someone at work pointed out this surprise in JavaScript: [] == ![] evaluates to true.

Reading this I thought it was stating something is equal to the opposite of itself.  For non technical readers can things be equal without being the same?  Currencies?  People?  In English do people sometimes say same but mean equal?

In programming worlds things which are not the same might be equal, but I expect something that is the opposite of itself to definitely not be equal to itself.  For example 1 is not equal to !1  I decided to discover how can this be?

I started by firing up a debugger and looking at the types [] and ![].  ![] is false*.

Then I went to the ECMA-262 spec:

Section 11.9.1 The Equals Operator (==) points us to 11.9.3 abstract equality comparison.

11.9.3 The Abstract Equality Comparison Algorithm
The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:
7.If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).

9.3 ToNumber
  Given Argument Type Boolean The result is 1 if the argument is true. The result is +0 if the argument is false.

Going back to 11.9.3

9. If Type(x) is Object and Type(y) is either String or Number, return the result of the comparison ToPrimitive(x) == y.

Section 9.1 ToPrimitive:
For input type Object

Return a default value for the Object. The default value of an object is retrieved by calling the [[DefaultValue]] internal method of the object, passing the optional hint PreferredType. The behaviour of the [[DefaultValue]] internal method is defined by this specification for all native ECMAScript objects in 8.12.8.

Section 8.12.8 DefaultValue

When the [[DefaultValue]] internal method of O is called with hint Number, the following steps are taken:

  1. Let valueOf be the result of calling the [[Get]] internal method of object O with argument "valueOf".
  2. If IsCallable(valueOf) is true then,
    1. Let val be the result of calling the [[Call]] internal method of valueOf, with O as the this value and an empty argument list.
    2. If val is a primitive value, return val.
  3. Let toString be the result of calling the [[Get]] internal method of object O with argument "toString".
  4. If IsCallable(toString) is true then,
    1. Let str be the result of calling the [[Call]] internal method of toString, with O as the this value and an empty argument list.
    2. If str is a primitive value, return str.
  5. Throw a TypeError exception.

valueOf defined in Section 15.2.4.4 does not return a primitive so toString() from step 3 is called resulting in ""

Going back to 11.9.3

5. If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.

Section 9.3.1 ToNumber Applied to the String Type informs us that whitespace returns 0.

The leaves us with ([].toString() == "") == (![] == 0) which can be confirmed in a debugger and also results in [] == ![] resulting in true.



*To know why ![] is false
See section 11.4.9

11.4.9 Logical NOT Operator ( ! )
The production UnaryExpression : ! UnaryExpression is evaluated as follows:
1.Let expr be the result of evaluating UnaryExpression.
2.Let oldValue be ToBoolean(GetValue(expr)).
3.If oldValue is true, return false.
4.Return true.

Step 2 ToBoolean(GetValue(expr))
Takes us to Section 9.2 ToBoolean where: for Argument Type Object the result is true.

Monday, February 15, 2010

Integrating FxCop into Visual Studio

At my previous company we had Visual Studio Team System (VSTS) which has Code Analysis (FxCop) integrated into Visual Studio. To turn it on one enters project properties and clicks on the Code Analysis tab. Each rule or group of rules is turned on by checking a box and the rules execute on every build of the project. I love FxCop because it teaches me how to be a better programmer, finds issues in my code, and makes my APIs more user friendly. I was disappointed upon discovering Code Analysis is a VSTS feature.

This post shows two options for getting FxCop 1.36 running on a each Visual Studio 2008 build without maintaining an FxCop project separate from a C# project.  On the downside it will run the same set of rules for each project, which works for my scenario but may pose problems when working with legacy code and new development because the legacy code will probably violate many rules.

This instructions assume the following environment:
  • MSbuild Version 3.5.30729.4926
  • 64 bit Windows (otherwise you will need to modify the C:\Program Files (x86) paths )
  • Visual Studio 2008
  • FxCop 1.36
Option #1: Integrating FxCop at the project level.
  1. Install FxCop
  2. Create a file: C:\Program Files (x86)\MSBuild\v3.5\FxCop.targets with the following text:
    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        <!-- Add FxCop to the list of targets to build -->
        <BuildDependsOn>$(BuildDependsOn);FxCop</BuildDependsOn>
      </PropertyGroup>
      <!-- Define the FxCop target we added above.-->
      <Target Name="FxCop">
        <Message Text="$(MSBuildToolsPath)" />
        <!-- The Condition attribute allows others to use the same project file without breaking their build when FxCop is not installed-->
        <Exec Command="&quot;$(ProgramFiles)\Microsoft FxCop 1.36\FxCopCmd.exe&quot; /file:&quot;$(TargetPath)&quot; /console"
              Condition="Exists('$(ProgramFiles)\Microsoft FxCop 1.36\FxCopCmd.exe')" />
        <!-- When running on a 64 bit machine the $(ProgramFiles) variable will be set to c:\program files (x86) when running a 32 bit process which luckily for us Visual Studio and FxCop are.-->
      </Target>
    </Project>
  3. Open the Visual Studio
  4. File --> New Project (ctrl+shift+n)
  5. Select Other Project Types --> Visual Studio Solutions --> Blank Solution
  6. Name the solution FxCopIntegrated and press OK
  7. In Solution Explorer (ctrl +alt + L) right click the solution and select add new project.
  8. Select Visual C# --> Windows --> Class Library
  9. Name the library CodeBandit and press OK.
  10. In Solution Explorer right click the CodeBandit project and click unload project.
  11. If Visual Studio prompts to save files click "yes"
  12. In Solution Explorer right click the CodeBandit project and click "Edit CodeBandit.csproj"
  13. Navigate to the line after this (ctrl+g 52 on my machine):
    <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  14.  Add this line to reference the file created in step 2:
    <Import Project="$(MSBuildExtensionsPath)\v3.5\FxCop.targets"/>
  15. In Solution Explorer right click the CodeBandit project and click reload project.
  16. If Visual Studio asks to close CodeBandit.csproj click "yes" and "yes" to save changes if prompted.
  17. Build the solution.  On my system I received these warnings:
    CA2210 : Microsoft.Design : Sign 'CodeBandit.dll' with a strong name key.
    CA1014 : Microsoft.Design : Mark 'CodeBandit.dll' with CLSCompliant(true) because it exposes externally visible types.
Option #2 Integrating FxCop across all solutions.
  1. Follow the steps from Option #1 to ensure everything is setup and working.
  2. Create a file: C:\Program Files (x86)\MSBuild\v3.5\Custom.After.Microsoft.Common.targets with the following text:
    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <Import Project="FxCop.Targets"/>
    </Project>
  3. Thats it, all the work was performed in Option #1 :)
  4. To verify this add a new VB project to the FxCopIntegrated solution.
  5. Building the newly added project I get these warnings:
    CA1020 : Microsoft.Design : Consider merging the types defined in 'ClassLibrary2' with another namespace.
    CA2210 : Microsoft.Design : Sign 'ClassLibrary2.dll' with a strong name key.
    CA1014 : Microsoft.Design : Mark 'ClassLibrary2.dll' with CLSCompliant(true) because it exposes externally visible types.
    CA1824 : Microsoft.Performance : Because assembly 'ClassLibrary2.dll' contains a ResX-based resource file, mark it with the NeutralResourcesLanguage attribute, specifying the language of the resources within the assembly. This could improve lookup performance the first time a resource is retrieved.
Thanks to John Robbins for pointing me to an old post by the Code Analysis team showing how to call FxCop in a post build event and having it run over the project without maintaining a separate FxCop project file.

Monday, February 8, 2010

Redirecting Assembly Bindings in .NET 3.5

I spent some time last week digging into assembly binding redirection.  This blog post provides working examples of assembly redirection through config files and publisher policies.

This example will use the following command line utilities and versions:
  • csc - C# compiler (Version 3.5.30729.4926)
  • sn - .Strong Name Utility (Version 3.5.30729.1)
  • gacutil - Global Assembly Cache Tool (Version 3.5.30729.1)
  • al - assembly linker (Version 8.00.50727.42)
Helpful utilities not covered in this article:
To get started lets create a program calling a method in another assembly which outputs the callee's assembly version.  These steps also create assemblies for use in the later examples.
  1. Open a Visual Studio Command Prompt and navigate to a working directory where some files can be created.
  2. Create and save a file named demo.cs containing the following text:
    using System;
    using System.Reflection;

    [assembly: AssemblyVersionAttribute("2.0.0.0")]

    public static class Demo
    {
        public static void Main()
        {
            Console.WriteLine("Version " + Assembly.GetExecutingAssembly().GetName().Version.ToString());
        }
    }
  3. from a command prompt type "sn -k key.snk"
  4. type "csc /target:library /keyfile:key.snk demo.cs"
  5. type "echo f | xcopy demo.dll .\bin\v2\demo.dll"
  6. Change the AssemblyVersionAttribute in demo.cs replacing "2.0" with "3.0"
  7. csc /target:library /keyfile:key.snk demo.cs
  8. echo f | xcopy demo.dll .\bin\v3\demo.dll
  9. Change the AssemblyVersionAttribute in demo.cs replacing "3.0" with "4.0"
  10. csc /target:library /keyfile:key.snk demo.cs
  11. echo f | xcopy demo.dll .\bin\v4\demo.dll
  12. Change the AssemblyVersionAttribute in demo.cs replacing "4.0" with "1.0"
  13. csc /target:libarary /keyfile:key.snk demo.cs
    1. echo f | xcopy demo.dll .\bin\v1\demo.dll
  14. Create and save a file named demo.cs containing the following text:
    public static class Program
    {
        public static void Main()
        {
            Demo.Main();
        }
    }
  15. csc /reference:demo.dll program.cs
  16. program.exe
  17. The output should read: Version 1.0.0.0
Redirecting 1.0 to 2.0 version in the GAC.
  1. gacutil /i .\bin\v2\demo.dll
  2. sn -T demo.dll
  3. Note the Public key token as we'll need that in the assemblyIdentity publicKeyToken attribute in the next step.
  4. Create program.exe.config with the following text:
    <?xml version="1.0"?>
    <
    configuration>
     <
    runtime>
      <
    assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <
    dependentAssembly>
        <
    assemblyIdentity name="demo" publicKeyToken="keyFromSn-T" />
        <
    bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
       </
    dependentAssembly>
      </
    assemblyBinding>
     </
    runtime>
    </
    configuration>
  5. program.exe
  6. The output should read:  Version 2.0.0.0
Redirecting 1.0 to Version 3.0 using a URL:
  1. Replace the program.exe.config text with the following:
    <?xml version="1.0"?>
    <configuration>
     <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <dependentAssembly>
         <assemblyIdentity name="demo" publicKeyToken="keyFromSn-T" />
         <bindingRedirect oldVersion="1.0.0.0newVersion="3.0.0.0"/>
            <!--to use an absolute filepath use href="file://D:/Projects/...." or it can point to a web resource: href="http://www.fake.com/demo.dll"-->
         <codeBase version="3.0.0.0" href="./bin/v3/demo.dll" />
        </dependentAssembly>
      </assemblyBinding>
     </runtime>
    </configuration>
  2. program.exe
  3. The output should read: Version 3.0.0.0
Redirecting 1.0 to Version 4.0 in the GAC using a publisher policy.
  1. Create a policy.config file in the working directory with this text:
    <?xml version="1.0"?>
    <configuration>
     <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <dependentAssembly>
        <assemblyIdentity name="demo" publicKeyToken="keyFromSn-T" />
        <bindingRedirect oldVersion="1.0.0.0" newVersion="4.0.0.0" />
       </dependentAssembly>
      </assemblyBinding>
     </runtime>
    </configuration>
  2. al /link:policy.config /out:policy.1.0.demo.dll /keyfile:key.snk
  3. gacutil /i policy.1.0.demo.dll
  4. gacutil /i .\bin\v4\demo.dll
  5. delete the program.exe.config in the working directory or erase the bindingredirect element.  The bindingredirects seem to be applied first and will break this example.
  6. program.exe
  7. The output should read: Version 4.0.0.0

Monday, February 1, 2010

A new life with Microsoft Dynamics CRM...

Friday January 15th was my last day at Urban Science where I learned a lot about software development and made a lot of great friends.

On Monday January 18th I started a new job at Sonoma Partners.  We specialize in customizing and implementing Microsoft Customer Relationship Management software for our customers.

If you are a technologist, programmer, personal contact, or professional contact in the Chicago area give me a call and lets get together.

If you are a potential Microsoft CRM customer, give me a call and lets make a deal ;)

Monday, January 25, 2010

NDepend

Patrick Smacchia kindly gave me the opportunity to use and evaluate his NDepend product.  NDepend is a static analysis tool meaning it can provides insight and guidance about one's work by inspecting assemblies and source code.  It identifies things like classes which may be better as structures by looking at the size of an instance of the class, the number of children, and the depth of inheritance.  It also graphically displays assembly dependencies and can do comparisons of an application between releases.  All in all a very cool tool!


First I started up NDepend to run it over a WPF desktop application I worked on in 2008.  I started by creating a new project.  It was very slick the new project open a .sln file to determine the assemblies to analyze.  NDepend understands there are application assemblies (assemblies compiled from the user's code) and tier assemblies (generally compiled references).  This picture shows what I mean.  After taking just 15 seconds to analyze 353,899 IL instructions NDepend showed an interactive view displaying many different views of the codebase at once which were all linked together, so if I drilled into something in one view or hovered over it there would be an effect in the other windows.  Being a noob this was a bit much for me and I opted to view a static HTML report.  The report didn't look so great in Chrome or FireFox but looked fine in IE8.  I read through the 50 page report awash in information.  I wish I had used the tool in 2008 to focus some of our refactoring efforts.  There are a lot of fantastic queries out of the box showing things that are blatantly wrong with the code we wrote.  Speaking of queries, NDepend has a very cool Code Query Language (CQL) one can use to write queries which throw errors or warnings during a build process.  NDepend comes with many queries out of the box which you can run or use as examples.  


Here is a query provided in the NDepend install showing types that could potentially be marked sealed:
// <Name>Class with no descendant should be sealed if possible</Name>
WARN IF Count > 0 IN SELECT TOP 10 TYPES WHERE
  
IsClass AND
  
NbChildren ==0 AND
  
!IsSealed AND
  
!IsStatic


Here is another query provided in the NDepend install showing classes that might be better as structures:

// <Name>Classes that are candidate to be turned into Structures</Name>
WARN IF Count > 0 IN SELECT TOP 10 TYPES WHERE 
  IsClass AND
  SizeOfInst <= 16 AND    // Structure instance must not be too big, else it degrades performance.
  NbChildren == 0 AND     // Must not have children
  DepthOfInheritance == 1 // Must derive directly from System.Object
  // AND IsSealed    : You might want to add this condition to restreint the set.
  // AND IsImmutable : Structures should be immutable type.
  // AND !IsPublic   : You might want to add this condition if you are developping a framework
  //                   with classes that are intended to be sub-classed by your clients.


These are two examples of things I would like to know but wouldn't like to take the effort to figure out.  NDepend makes time consuming code analysis tasks simple and shareable by providing the Code Query Language.

A couple months later I decided to use NDepend to analyze the ASP.NET solution I worked on in 2009.  I precompiled the application as recommended in the NDepend FAQ and browsed to that output instead of using the ASP.NET solution file to begin my analysis.  Unfortunately this project's code quality wasn't as high as the other project and there were 491,298 IL instructions for NDepend to analyze, although it only took 13 seconds. :)  Again I mostly skipped the UI and dove into the 492 page report.  Being a web app, some of the assemblies have funky names like App_Web_c55buezi which makes some items in the report harder to consume than the human friendly names from the desktop project.  Unfortunately I will not be working on this codebase anymore and did not have significant ownership of it so I didn't diligently read up all the goodness NDepend was giving me access to.

My lesson learned is that I need to run this fabulous tool over code I'm actively working on so I can take advantage of it and learn like I've learned from FxCop.  This tool is great because it has something for everyone.  From rules with specific recommendations on what to fix to strategic insights into your dependency structure.

Monday, December 7, 2009

Ensuring lambdas don't leak when passed to EventHandlers

I'm writing a wrapper around a class which outputs results of commands executed into a stream buffer.  I wanted to capture the command text and return that to the caller of my wrapper.  I wanted to use a lambda and clean up my delegate after the command returned.  This contrived code sample shows how to do this improperly and properly:



static void Main()
{
    ExecuteCommand();
    Debug.Assert(CommandExecuted == null);
    ExecuteCommandLeaks();
    //This assert will fail
    Debug.Assert(CommandExecuted == null);
}

static void ExecuteCommandLeaks()
{
    CommandExecuted += new EventHandler<EventArgs>((o, e) => Console.WriteLine("Event called"));

    CommandExecuted.Invoke(new object(), new EventArgs());
}

static void ExecuteCommand()
{
    var commandCapture = new EventHandler<EventArgs>((o, e) => Console.WriteLine("Event called"));
    CommandExecuted += commandCapture;

    CommandExecuted.Invoke(new object(), new EventArgs());

    CommandExecuted -= commandCapture;
}

static EventHandler<EventArgs> CommandExecuted;


Monday, November 23, 2009

SQL Server Management Studio Generating Change Scripts

For those of you who need to lookup SQL syntax for things like alter table, this will let SQL Server Management Studio (SSMS) do the work for you giving you a baseline script to modify or check right into source control.

Generating an Alter Table Statement:

  1. In SSMS use the object explorer to navigate to a table.
  2. Right click and select design.
  3. Make your changes.
  4. From the menu select Table Designer --> "Generate Change Script..."
  5. Copy and paste the script text or click the yes button to save it to a text file.

Adding a Foreign Key:

  1. In SSMS use the object explorer to navigate to a table.
  2. Expand the table node.
  3. Right click on Keys  and select "New Foreign Key..."  Notice this brings up the table designer if it isn't already open.
  4. Fill out the new FK and click Close
  5. You should now be in the table designer.  Follow the steps from above.

Monday, November 9, 2009

Delete a Blogger Comment

To delete a blogger comment, like spam, the easiest way I have found to do it is by

  1. Opening the post I want to delete in Chrome (the technique should work in any browser, but Chrome is my favorite because it is much faster than IE and because I like the Google brand better than FireFox)
  2. Right Clicking on the page and selecting "View page source"
  3. Press ctrl+f to bring up the search box and enter "delete".
  4. Look for the delete link.  It was the second search result on the page for me and looked like this: <a href='http://www.blogger.com/delete-comment.g?blogID=5094545033872573936&postID=6517665474722511356' title='Delete Comment'>
  5. Click the link.
  6. Follow the directions on the next page confirming the deletion.
There is probably a way to make the delete button show up on the page but I don't know how.

Monday, November 2, 2009

TEDxDetroit recap

My cousin, Gabriel Mott, turned me on to TED in 2005 by linking to what is still my favorite TED talk. I was excited to be accepted as an attendee of the inaugural TEDxDetroit event on 10/21/2009 at Lawrence Tech University.

The most beneficial part for me was speaking with other attendees such as Alex Fisher, Henry Balanon, Bret Kopf, Betsy Weber and meeting new people such as Lisamarie Babik, David Benjamin, Andrew Brown, Jamie Favreau, Lee Andros (bus buddy!), Janak Mehta, Rich Sheridan, and Dug Song.

Here are my take aways:

  • Ask high quality questions.  High quality questions provoke thought.  An example could be "How can we generate y revenue through x technology?",  "How can social media help solve world hunger?"
  • What can we do now given the current technology and environment?  If our plans depend on a change (new technology, etc) what if that change doesn't manifest?  If our plans don't consider the current environment (ie. culture) how will the implementation go?
  • There are two ways to make money, by nickel and diming the competition or by taking big leaps over them.  Giants take big leaps.  Who are your giants?
  • Users are not stupid. Designs are stupid.  Observer your users in their environment and reduce their pain.
  • Some people are economic hurricanes.  Everyone has great ideas.  Those who execute on those ideas are the hurricanes.
  • Research the problem before providing the solution.  When we have ideas we think of our solution and present that.  Instead of presenting that, present the problem inspiring your solution and see what others have to say.
  • At a certain level of wealth problems are problems of perception.  This was a particularly interesting talk for me because I tend to think in functional terms instead of presentation.
    • All value is relative.
    • Persuasion is better than mandates.
    • Contextual timely and immediate.
P.S. If you would like to attend a regional TED event, TEDxLansing is seeking volunteers.