In Visual Studio 2010, Microsoft introduced the Managed Extensions Framework as an easy way of providing and consuming Visual Studio services, making it very easy to extend core VS components like the editor. There is a minor problem – extension components installed under the VS\Common7\IDE\Extensions subdirectory are not bypassed when you start Visual Studio using the /rootsuffix exp switch.
The EXP hive in Visual Studio provides a way of loading extensions you are developing and don’t want to install into the production version of Visual Studio you are using to develop the extension. Diagrammatically, it looks like this:
When you load a package under the EXP hive, you don’t want to load its production sibling at the same time. Loading two similar assemblies into the same process causes all sorts of unpredictable problems. The older COM based package loading mechanism in Visual Studio worked by creating a separate registry hive (with the suffix exp in its key) that ensured this never happened.
Visual Studio finds MEF extensions by scanning several known locations for files called extension.vsixmanifest. These manifests are XML files which name the packages and MEF extensions that Visual Studio should load. One of these known locations is \program files\Microsoft Visual Studio 2010\Common7\Ide\Extensions. Any manifests found in subdirectories below this location are always loaded by Visual Studio.
Another known location is C:\Users\user\AppData\Local\Microsoft\VisualStudio\10.0Exp\Extensions (this is the location under Windows 7 - it might be slightly different under other versions of Windows). Subdirectories under this location are only scanned when you start Visual Studio using the /rootsuffix exp switch.
Here's the problem - any MEF components listed in a manifest under program files\Visual Studio always get loaded when you start Visual Studio with /rootsuffix exp, even if there are development ones under AppData which are the ones you are actually interested in debugging. You can only stop this happening by editing your manifest under program files\Visual Studio to remove the references to MEF components.
The MEF Switch provides a simple way of seeing which MEF components are loaded by your extension.vsixmanifest, and enabling or disabling them easily. It is a short WPF application written in Visual COBOL. You can get an evaluation copy of Visual COBOL from here: http://vs2010.microfocus.com/visual-cobol.html. Or if you prefer, you can download the COBOL code that comes with this article and translate it to VB or C#. Since this utility uses only standard .NET framework functionality, rather than the things that only COBOL does easily (like 38 digit decimal arithmetic or indexed file handling) this should not be hard.
An extension.visxmanifest file looks like this:
<Name>Some Visual Studio Package</Name>
<Description>Detects Moriarty, edits clues</Description>
All the MEF Switch does is look for the
MefComponent elements, and display them to you. If you want to disable them, it comments them out. And it will reenable them by uncommenting them. Having been working on MEF extensions for a while, I find that leaving the MEF switch running somewhere on your desktop is a much easier way to see and change whether or not your extensions are going to be loaded from Program Files\Visual Studio then repeatedly studying and editing an XML file. Because the manifest it is editing is under program files, on Vista/Windows 7 you'll need to start your editor with elevated privileges for it to be able to save the changes. I usually start the MEF switch with elevated privileges at the start of a development session and leave it running till I'm finished. It doesn't keep the file locked, and saves the manifest automatically everytime you make a change.
Using the Code
The MEFSwitch looks like this when it's running:
It only reads one extension.vsixmanifest file, based on a path relative to your Visual Studio installation directory. This relative path is hardcoded because the shape of our product is such that we only have one extension directory, and I'm assuming that this is fairly typical. Making it work on a single manifest means that when you start it up everything is ready to go, but if this doesn't work for you, feel free to modify the code. The relative path is stored in a level 78 item (that's COBOL for
const) called VC-EXTENSION-PATH in VsixManifest.cbl.
The list view shows all the MEF components currently listed in the manifest. True indicates that they will be loaded by the next instance of Visual Studio started, False shows that they are commented out in the manifest and will be skipped. Double-click a status to change it or click one of the pushbuttons to change everything. Either way, the changes are saved immediately to the manifest file. Changing the status of an item has no effect on any Visual Studio instances already running - the manifest is only read at startup.
The MEF Switch has three important classes:
VsixManifest class represents the extension.vsixmanifest. It reads the XML file at startup using the
XmlDocument class in the framework, and creates an
ObservableMefList which contains
MefItem class describes a single
MefComponent entry in the manifest file. It has a WPF Dependency Property of Enabled which keeps the
ListView in the application window updated. The
ObservableMefList is defined in the same source file - it just inherits from
ObservableCollection but with the generic parameter set to be a
- Window1 is the WPF window which contains a textbox showing the location of the manifest that has been read, and the
ListView which displays the items. The
ctor sets the list view up to display a grid, reads the manifest (using the
VsixManifest class), and binds the list view to the
ObservableMefList. It has an event-handler which toggles the status of a
MefComponent everytime an item in the list view is double-clicked as well as event handlers for the two pushbuttons.
Points of Interest
Why did I write this in Visual COBOL? Mainly to show that a WPF app like this can be written in any .NET language, and I get tired seeing articles, blog posts etc, that go on about how redundant and long-winded COBOL is. In Visual COBOL, I don't think this app would be any shorter if translated, say to Visual Basic, and not much shorter in C#. So I suppose I'm making a point.
- 19th September, 2010: Initial version