Dotneteers.net
All for .net, .net for all!

DevTools Ecosystem Summit: Best Practices for Extending the IDE with a Focus on Performance, Part 3

<Part 2

image

In the last section of my presentation I would like to show you common mistakes or pitfalls, and try to give you a few tips to cope with them.

One of the most difficult issues to solve is when package load failures occur. The main reasons why these issues occur are generally

  • exceptions in Initialize or
  • Loading failure of a referenced assembly, generally because the assembly is not on the probing path of Visual Studio.

This kind of errors are very annoying, because prevent any functions of our package working. Because packages are loaded on-demand by default, we can face package initialization issues unexpectedly.

VS 2008 does not leverages on WPF technology. With VS 2010 you can compile packages using WPF tool windows successfully, but when you try to show them, their caption is visible but the client area does not show up.

The Visual Studio Command Table files (.vsct) also can have traps you can walk into. You can easily write a VSCT that compiles well, but does not show up your commands, because it has some semantic issues.

I also would like to show you, how you can trace your packages to get some diagnostic information for troubleshooting.

image

Let’s start to walk into a few traps…

I modify the Initialize method of the CSharpStats package so that it tries to use a service before that service has been initialized, and so causes a NullReferenceException.

  1. protected override void Initialize()
  2. {
  3.   base.Initialize();
  4.  
  5.   // --- This will fail:
  6.   var csharpSrv = GetService(typeof(SCSharpStats)) as ICSharpStats;
  7.   csharpSrv.GetCSharpFiles();
  8.  
  9.   // --- Proffer the service instance
  10.   var serviceContainer = this as IServiceContainer;
  11.   serviceContainer.AddService(typeof(SCSharpStats), new CSharpStatsService(), true);

When we build and run the package and want to display the C# Statistics window, we have a package load failure message:

image

With the help of the debugger you can find the source of this error. Answering with Yes to this question means that you will see the error message continuously when Visual Studio tries to load your package. However clicking on now will suppress this message and what we see is only that tool window does not show up. We do not see that it is a package load failure! Start the package with debugging to catch the source of the issue!

image

The debugger stops at the code line raising an exception, and we can see which code line is responsible to prevent our package load. However, we are not also as lucky as in this case. Visual Studio has a so-called activity log where VS puts diagnostics messages. This log is turned off by default, but you can turn it on with the /log command line switch. To debug your package with the Experimental Instance, you have to change your project’s debug properties:

image

When running our faulty package again, we can look into the log file. This file can be found under your roaming profile in the Microsoft\VisualStudio\10.0Exp folder. In this file we can see that our package failed to load.

image

We can put our own messages into the activity log, CSharpStats also does it at the end of the Initialize method:

  1.   var refreshCommandID = new CommandID(GuidList.guidCSharpStatsCmdSet,
  2.     (int)PkgCmdIDList.cmdidRefreshCSharpStats);
  3.   var menuRefresh = new MenuCommand(RefreshStats, refreshCommandID);
  4.   mcs.AddCommand(menuRefresh);
  5.   
  6.   // --- Log initialization success
  7.   ActivityLog.Write("CSharpStats", "Package initialization done.");
  8. }

Now, when we delete the two fake lines preventing our package to load, and run the package again, the activity log shows our package gets loaded.

image

You can also discover messages the C# Statistics tool window put into the log.

Now, let’s examine a new potential issue that is new in VS 2010, and it is related to WPF tool windows. You can put semantic mistakes into the XAML definition of your tool window so that your project compiles, but the tool window does not work. I show you what phenomena escort this issue. Let’s put a semantic mistake into our tool window definition:

  1. <DataGridTextColumn Header="Types" Binding="{Binding Types}"
  2.                     Width="Auto" IsReadOnly="True"
  3.                     ElementStyle="{StaticResource QNumericCellStyle}" />

Here, I changed the NumericCellStyle static resource name to QNumericCellStyle, which is faulty, as there is no such static resource. Despite of this change, our package will compile. When the tool window is about to show, we can meet with two kind of behavior. If the tool window was persisted before, when it is to be displayed at Visual Studio startup time, we can see the frame of the window, but its client area is hidden:

image

When the tool window is not persisted, at creation time we get the following message:

image

Fortunately, debugging will help to find out what the reason of this message is. Start the Experimental hive in debug mode and try to display the tool window. The exception caught helps you to discover that actually creating the window pane control fails:

image

Well, this message helps to discover the location of the failure but not its cause. Click on the View Detail link in the exception popup and you’ll be wiser:

image

This message tells that the problem is the name of the static resource we try to use.

The VSCT files also are sources of similar issues. The VSCT compiler checks the syntax and does a few semantic checks, however, does not check all things that actually could be checked at compile time. When the VSCT file is merged with the Visual Studio menus, further checks are done, and faulty commands or UI elements are simply not merged into the VS menu. However, there are checks that occur only at runtime.

So, when our VSCT file has some semantic errors, it could lead to unexpected issues. Let me show one of them. I modify the VSCT file so, that the refresh button of the tool window tool bar is parented directly in the <Menu> item representing the tool bar and not in the <Group> element that is the logical container for the Refresh button. The original definition is:

  1. <Button guid="guidCSharpStatsCmdSet" id="cmdidRefreshCSharpStats"
  2.   priority="0x0100" type="Button">
  3.   <Parent guid="guidCSharpStatsCmdSet" id="RefreshToolbarGroup"/>
  4.   <Icon guid="guidOfficeIcon" id="msotcidRefresh" />
  5.   <Strings>
  6.     <CommandName>RefreshProcessList</CommandName>
  7.     <ButtonText>Refresh Process List</ButtonText>
  8.   </Strings>
  9. </Button>

I  change it to:

  1. <Button guid="guidCSharpStatsCmdSet" id="cmdidRefreshCSharpStats"
  2.   priority="0x0100" type="Button">
  3.   <!-- I've changed the parent id -->
  4.   <Parent guid="guidCSharpStatsCmdSet" id="CSharpStatsToolbar"/>
  5.   <Icon guid="guidOfficeIcon" id="msotcidRefresh" />
  6.   <Strings>
  7.     <CommandName>RefreshProcessList</CommandName>
  8.     <ButtonText>Refresh Process List</ButtonText>
  9.   </Strings>
  10. </Button>

This is a semantic error, the VSCT compiler does not show any error, so we can run our package. However, when we want to display the tool window, we get the following message:

image

When we try to display the window second time, we face with another message:

image

Just as before, we can turn to our good friend, to the debugger. Let’s start the package in debug mode and see where it breaks!

image

As you see, it breaks in the ShowToolWindow method when calling the FindToolWindow method, so the exception is thrown in a method that is within the Managed Package Framework. This kind of exception at the point is thrown when the shell is about putting together the window frame, the window pane and the related toolbars. By my experience, generally this message means that your VSCT file has issues, like the one I put in the file above.

image

As a summary of the presentation, I would like to summarize my main messages on this slide. I would encourage you to leverage on WPF and MEF as they are great technologies helping you writing your extensions for VS 2010.

To be frugal or let’s say conservative with resource consumption, be lazy with loading your components and objects owned by your component.

Keep your UI always responsive and used idle loading wherever it is possible.

In order to cope with common package mistakes, use techniques helping to recognize while your packages fail.

Thank you for your attention!

 


Posted Oct 22 2009, 05:19 PM by inovak

Comments

DevTools Ecosystem Summit: Best Practices for Extending the IDE with a Focus on Performance, Part 2 - DiveDeeper's blog - Dotneteers.net wrote DevTools Ecosystem Summit: Best Practices for Extending the IDE with a Focus on Performance, Part 2 - DiveDeeper&#39;s blog - Dotneteers.net
on Thu, Oct 22 2009 17:57

Pingback from  DevTools Ecosystem Summit: Best Practices for Extending the IDE with a Focus on Performance, Part 2 - DiveDeeper's blog - Dotneteers.net

Add a Comment

(required)  
(optional)
(required)  
Remember Me?