Targeting an extension for VS2010 and VS2012 using a single manifest

Hi VS coders!

Today I want to share our experience on targeting extensions to Visual Studio 2010 and 2012 in the same package.

What do we achieve with this?

  • A single .vsixmanifest file.
  • A single extension Id
  • Publish your extension in a single page of the Visual Studio Gallery

One side effect is that at the end of the migration, you must use Visual Studio 2012. We investigated possible ways to create a version of the solution to be compatible with 2010 as well, in our case, it was not possible for reasons I will describe later.

Ok, too much introduction! let’s go to the first step:

1. Changes in the vsixmanifest file:

When you first open your solution created in VS2010 in VS2012, it will try to migrate the extension project. Some interesting thing I’ve learned here:

  • The .sln file is compatible for both Visual Studio versions.
  • There is a new version of the vsixmanifest schema, but the migration process won’t attempt to migrate it (that is good because we want our extension to be backward compatible). This is the reason why after the migration, VS2012 can’t open the file with the editor, instead it directly shows you the xml.

Ok, so, in order to let your extension be able to detect VS2012 you have to add this lines in the manifest.

<VisualStudio Version="11.0">
<Edition>Ultimate</Edition>
<Edition>Premium</Edition>
<Edition>Pro</Edition>
</VisualStudio>

of course the actual flavors of VS you support depends on your extension.

 

2. Split the extension:

After changing the manifest you can compile your extension and see if it works on VS2012. In some cases it should work, but we had problems with the following assembly:

  • Microsoft.VisualStudio.ExtensibilityHosting

As we are using MEF inside our extension, we depend on that assembly. The point is you can’t use version 10 inside VS2012, it simply won’t work. Because of this problem, we ended up splitting the projects in the following way.

 

image

We keep the extension project (the one that contains the manifest) targeting .NET framework 4.0 which contains only references to assemblies that are compatible with VS2012  and we create two other specific projects:

  • Extension.v10 –> .Net 4.0 (this project in our case contains references to Microsoft.VisualStudio.ExtensibilityHosting v 10.0.0)
  • Extension.v11 –> .Net 4.5 (this contains Microsoft.VisualStudio.ExtensibilityHosting v 11.0.0)

Some considerations:

  • The extension project should contain references to Extension.v10 and Extension.v11 (the key here is to set the property “Reference output assembly” to false so the compile in .Net 4.0 despite Extension.v11 targets 4.5).
  • Don’t forget to add references to both assemblies in vsixmanifest
<Assembly AssemblyName="Extension.v10">|Extension.v10|</Assembly>
<Assembly AssemblyName="Extension.v11">|Extension.v11|</Assembly>

3. Dynamic load

When your extension is executing, depending on the Visual Studio version it’s running on, it should load the specific assembly for that version . To do that, ask the DTE about the version. Within your Package class, you can use a code similar to this to complete the job:

private const int MaxVsVersion = 11;

protected bool IsVisualStudio2010
        {
            get { return GetMajorVsVersion() == 10; }
        }

private int GetMajorVsVersion()
        {
            DTE dte = (DTE)this.GetService(typeof(DTE));
            string vsVersion = dte.Version;
            Version version;
            if (Version.TryParse(vsVersion, out version))
            {
                return version.Major;
            }
            return MaxVsVersion;
        }

Finally, load the assembly accordingly

 FileInfo assemblyFilename;
            if (IsVisualStudio2010)
                assemblyFilename = new FileInfo(Path.Combine(packageLocation,"Extension.v10.dll"));
            else
                assemblyFilename = new FileInfo(Path.Combine(packageLocation,"Extension.v11.dll"));

            Assembly assembly = Assembly.LoadFrom(assemblyFilename.FullName);

 

Then, you can use reflection or MEF to resolve what you need (the following code is an example using MEF)

var catalog = new AssemblyCatalog(assembly);
            var bootstrapContainer = new CompositionContainer(catalog);

            var export = bootstrapContainer.GetExportedValue<IBootstrapper>();
            container = export.GetContainer();

Hope It helps!

Hernán

  • Hernan Veiras

    Software Developer

    I’ve been working as a Software Developer professionally for the last six years. During these years I gained experience developing enterprise oriented solutions such as intranets, portals and other web applications. Nowadays I’m looking forward to work more closely to research areas. In my spare time I like to travel, read and learn new stuff.

Leave a Reply




December 19, 2014

Faltan dos días para el cierre de inscripción. Ya enviaste tu CV? http://t.co/lcTrvWlOsv