Extended properties MEF usage is incompatible with VS MEF


VS has built-in support for multiple MEF catalogs via the VsCatalogNameAttribute (see http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.extensibilityhosting.vscatalognameattribute.aspx).

Using this support, another catalog can contribute extensions to the VS global composition container, using the appropriate VsExportSharingPolicy (see http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.extensibilityhosting.vsexportsharingpolicy.aspx and explained http://blogs.clariusconsulting.net/pga/vs-10-beta-1-exporting-mef-parts-from-a-vs-package-part-1).

This works perfect for things like exposing text editor adornments, outliners and the like. That is, a custom catalog CAN provide exports to the global VSMEF container so that other components (i.e. the editor, or the EF designer) can retrieve those extensions.

However, I couldn't make this work at all with the EF designer. Turns out (apparently in my reflector investigations), that the EscherExtensionPointManager is the culprit, since it's doing this highly suspicious work:

private void Init()
ComposablePartCatalog catalog = (PackageManager.Package.GetService(typeof(SComponentModel)) as IComponentModel).GetCatalog("Microsoft.VisualStudio.Default");
this._compositionContainer = new CompositionContainer(catalog, new ExportProvider[0]);

From that point on, it's completely against the VSMEF behavior, since the EFAnnotatableElementDescriptor<TEFElement>.LoadPropertyDescriptorExtensions now uses THAT container to lookup exports, rather than the IComponentModel.DefaultExportProvider!

Investigating further, this reveals a more serious issue with the given approach: all exports from the VS MEF default catalog will get instantiated twice because of this custom private composition container, even when their part creation policy might indicate a shared instance. This is because this code is pulling just the catalog, and then building a new container. Exports on the VS global container will not be reused here, but will be instantiated again.

And the worse part, not even the omniprescent IServiceProvider export in VS works, which works on every other place within VS MEF :S
    public IServiceProvider ServiceProvider { get; set; }
Yes, someone could use ServiceProvider.GlobalServiceProvider, and any number of other workarounds. But the question remains: should this particular area adhere to VS extensibility in a more compatible way?

The attached solution contains 2 VSIX projects:
  • FailsToImportFromCustomCatalog: showcases how using a custom catalog makes an EF extended property dissapear. But at the same time showcases that a simple editor adornment works just fine, custom catalog or not.
  • FailsToImportServiceProvider: shows a straightforward VSIX with no custom catalog, package or anything. Just an export that fails when you import SVsServiceProvider, and succeeds when you don't.

file attachments


RoMiller wrote Nov 29, 2012 at 11:33 PM

EF Team Triage: We should look at doing this in EF6. We may accept a contribution for this once the designer is OSS.

RoMiller wrote Jan 16, 2013 at 8:49 PM

We are only taking minimal changes to the designer in EF6 because we are still converting the code base to open source. We'll consider this bug for the next release.

We would accept a contribution once the designer is OSS.