31 October 2008

Wild World of Visual Studio -- Mysterious Component

This one was bugging us for a long time, until we got message from Jay (thanks!) who had similar problem and was willing to help.

Story 2 -- Mysterious Component

The problem itself is mysterious. From time to time it happens that Visual Studio stops loading any add-ins. ReSharper is installed, but its menus are suddenly all gray and it is not listed in the "Tools \ Add-in manager" dialog. It happens after installing various products, it could be service pack, SQL server tools, Visual Studio components - anything! Some users install them and all works fine. Some users loose their favorite productivity tool.

Logging, debugging, trying to reproduce for may be several years(!) led to no result. ReSharper was simply not loaded into the process, though all registration information appears to be in the right place. We checked encodings, verified files are not corrupted, verified registry access rights - all we can think of. As you can guess now, the reason was not anywhere near.

After lots of email exchanges with Jay, including mini-dumps, Process Monitor traces, registry excerpts, configuration files and such we suddenly found ourselves staring at the right thing. It was msxml6.dll. Actually, it was the fact that there were no msxml6.dll in the call stack. Instead, there was msxml3.dll.

We use .addin files to register our add-in in Visual Studio. It is XML file describing add-in, containing information about primary assembly, descriptions, load options and Visual Studio version compatibility information. The latter was that msxml3 was not able to process and thus Visual Studio refused add-in as non-compatible. In fact, msxml6 was there in System32, but it somehow happened to be not registered as COM object. Using regsvr32 on msxml6.dll repaired the system, resurrected ReSharper and enabled customers to enjoy our productivity add-in again.

Case closed.

30 October 2008

Wild World of Visual Studio -- Unfriendly Package

While developing "The Most Intelligent Add-In To Visual Studio" we often face issues that originates from the outside of our code. Being that Visual Studio itself, other packages and add-ins installed, OS components or other things added to the mix - it is always extremely hard to reproduce, debug and understand. Usually we have to perform post-mortem debugging, when all we have is mini-dump from the user experiencing the crash. And we are very happy when we have mini-dump! Often we have to resort to psychic debugging, speculating about what could have happened, trying this and that until we find the cause and issue the fix.

I though I could share some stories of pure insanity we happened to participate in recently. May be another add-in developer is scratching his head in an attempt to understand the source of strange sounds from beneath the ground, and these stories will help. Or it may be just interesting reading for you. Or not :)

The first one is the most recent one and is pretty simple.

Story 1 -- Unfriendly Package

Our customers were complaining about Visual Studio crashing on start with ReSharper installed when running non-admin. Disabling ReSharper allows Visual Studio to load normally. When you see such behavior, you are absolutely sure ReSharper is guilty, aren't you?

We've learned to be cautious in such cases. So I asked user (thanks Jon!) to capture mini-dump and send it to me for investigation. While downloading it, I was preparing myself to long hours of WinDbg magic, but !ClrStack revealed it in a second. SnippetDesigner was not able to access its files, since it placed it in privileged folder. It did so in the background thread and didn't catch exceptions. The result is CLR termination, which get Visual Studio to nowhere with itself.

But wait! Why disabling ReSharper helped to avoid crash? Well, actually crash happens during SnippetDesigner package loading. Normally, it occurs when its window is opened (and it indeed crashes VS at this point without ReSharper). However, ReSharper uses Visual Studio API to get some configuration information, which can be extended with packages. So, by calling this API ReSharper caused those packages to load, essentially triggering the bug in SnippetDesigner on startup.

Case closed, opened another one.

06 October 2008

ReSharper Combos - Hiding Details

Today my day started with the question from Oleg Stepanov, Project Manager of ReSharper. He asked about avoiding huge amount of manual code changes, and after short discussion we got it done with ReSharper. I was very excited! We were able to solve refactoring task in seconds, invent new refactoring combo, and ReSharper was so smart to handle it absolutely right. No manual code changes outside of the type being refactored. Here is simplified version of what we had, what we were to accomplish and how we did it.

  public class Person
  {
    public string Name { get; set; }
    public int Age { get; set; }
  }
 
  public class PersonInformation
  {
    private readonly Person myPerson;
 
    public PersonInformation(Person person)
    {
      myPerson = person;
    }
 
    public Person Person
    {
      get { return myPerson; }
    }
  }
 
  internal class Processor
  {
    private readonly PersonInformation myPersonInformation;
 
    public Processor(PersonInformation personInformation)
    {
      myPersonInformation = personInformation;
    }
 
    public int Process()
    {
      switch (myPersonInformation.Person.Name)
      {
        case "Mike":
          return 1;
        case "Sally":
          return myPersonInformation.Person.Age > 30 ? 2 : 3;
      }
      return myPersonInformation.Person.Age < 20 ? 0 : 1;
    }
  }

Consider PersonInformation class above. We wanted to decouple it from Person class and make it store Name and Age itself. However, we had a lot of usages like in Processor.Process, where Person property was being used to access Name and Age. How would we do it?

First, we use Generate (Alt-Ins) and select Delegating Members to generate Name and Age properties in PersonInformation class:

    public string Name
    {
      get { return myPerson.Name; }
      set { myPerson.Name = value; }
    }
 
    public int Age
    {
      get { return myPerson.Age; }
      set { myPerson.Age = value; }
    }

Then we change Person Property to return PersonInformation instead. Since there are all required properties already, usages are not broken. They are now routed through delegating members and use Name and Age properties of PersonInformation:

    public PersonInformation Person
    {
      get { return this; }
    }

And here magic happens, we use Inline Property refactoring to get rid of the property!

  public class Person
  {
    public string Name { get; set; }
    public int Age { get; set; }
  }
 
  public class PersonInformation
  {
    private readonly Person myPerson;
 
    public PersonInformation(Person person)
    {
      myPerson = person;
    }
 
    public string Name
    {
      get { return myPerson.Name; }
      set { myPerson.Name = value; }
    }
 
    public int Age
    {
      get { return myPerson.Age; }
      set { myPerson.Age = value; }
    }
  }
 
  internal class Processor
  {
    private readonly PersonInformation myPersonInformation;
 
    public Processor(PersonInformation personInformation)
    {
      myPersonInformation = personInformation;
    }
 
    public int Process()
    {
      switch (myPersonInformation.Name)
      {
        case "Mike":
          return 1;
        case "Sally":
          return myPersonInformation.Age > 30 ? 2 : 3;
      }
      return myPersonInformation.Age < 20 ? 0 : 1;
    }
  }

Look how Processor now uses Name and Age directly on PersonInformation class and has no idea about Person class used inside! Now the fact that PersonInformation uses Person is implementation detail and we can change it any way we like.

Refactor With Pleasure!

03 October 2008

ReSharper Guidelines -- First Time Users

Harry L. wrote in review of ReSharper on Visual Studio Gallery:
... I have found that I used the features of Resharper almost without knowing it. What amazed me was how many features I use without going up a long learning curve...

Indeed, most important ReSharper features can be instantly learned right from the code editor without reading any documentation. However, I thought that having some guidelines about where to look and how to improve own productivity would be nice anyway. So I'm going to write several posts about how to use ReSharper in a form of guidelines.

Shortcuts are given for Visual Studio keyboard scheme, but you can easily find shortcuts for your configuration in ReSharper menu.

First Time Users guidelines:


  1. DO open your real project in Visual Studio with ReSharper enabled. Playing with the productivity tool in a sandbox doesn't really give you understanding about its effect. It can take some time for ReSharper to analyze your solution for the first time, but it will be much faster during subsequent runs.

  2. DO NOT run away from your Visual Studio when you first open your source code with ReSharper :) You will see colored identifiers, a lot of squiggles indicating warnings and suggestions, redundant code painted in gray -- your code most likely will be overhighlighted. You will clean it up pretty fast with ReSharper. You can switch Color Identifiers off if you wish (ReSharper / Options / Code Inspection / Settings).

  3. DO configure your naming (ReSharper / Options / Languages / Common / Naming Style) and formatting preferences (ReSharper / Options / Languages / C# / Formatting Style). ReSharper uses these settings when guessing on identifiers, while updating the code and doing other automatic code generation and transformation for you.

  4. DO learn 4 keyboard shortcuts to use in code editor:

    • Alt-Enter - opens code transformation menu with Quick Fixes and Context Actions. Try it whenever you see light bulb to the left of your code, and see what you can do with it.
    • Alt-` (Navigate from Here) to open menu with actions to navigate from currently selected symbol, like "Go to base", "Go to derived" and "Go to usages"
    • Alt-Ins (Generate) -- generates type members, like properties, constructors, overrides and implementations, Equals, GetHashCode and ToString methods.
    • Ctrl-Shift-R (Refactor This) -- opens menu with all refactorings available at current caret position (or current selection in any ReSharper tool window).

  5. DO NOT use Solution Explorer to find code, use "Go to Type" (Ctrl-T), "Go to File" (Ctrl-Shift-T), "Recent Files" (Ctrl-,) and other commands from ReSharper / Go To menu. This will help you navigate much faster.


After you familiarize yourself with these basic actions, download and print key map and start exploring other commands.