How can a VS extension target multiple versions in regard to Microsoft.VisualStudio.* references? - visual-studio

A few extensions that I'm using are broken under VS2012 because at some point they were updated to work with VS2013, by changing the version of referenced libraries. At runtime an error like this can be produced:
Could not load file or assembly 'Microsoft.VisualStudio.Shell.12.0, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.
I see various extensions referencing multiple versions of the same library:
<Reference Include="Microsoft.VisualStudio.Shell.Interop" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop.8.0, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop.9.0, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
Others release an extension per VS version.
Another option, according to this article, is to dynamically load the correct version.
I'd like to help fix these extensions, but what's the proper way to tackle this issue?

So the Visual Studio reference assemblies break down into a few different categories, which you should handle differently depending upon the category:
Interop assemblies: these are the ones like the Interop.* assemblies you listed in your question. Each interop assembly isn't a newer version of the "same" thing, but rather an assembly that contains all the COM interfaces that were added in that version of Visual Studio. Referencing old versions is fine, just don't reference a newer one than the lowest version of Visual Studio you want to target
Editor assemblies, Roslyn: Anything related to the core text editor (assemblies are Microsoft.VisualStudio.Text.Data, Microsoft.VisualStudio.Text.UI, Microsoft.VisualStudio.Text.UI.Wpf, and Microsoft.VisualStudio.Editor) and Roslyn Visual Studio includes assembly redirects that redirect whatever version you're referencing to the version of VS you're actually running in. Once again, target the lowest version that you intend to support.
Microsoft.VisualStudio.Shell.[version]: this one confuses people a lot. How this particular assembly works is for each version of Visual Studio that ships, a new assembly name (with the version in the assembly) is made. Then, in future versions of the Visual Studio, we ship a newer version of the assembly that you target. So again, make sure you're targeting Microsoft.VisualStudio.Shell.[version] with the lowest version you intend to support.
The tricky problem here is the VSSDK project upgrader likes to upgrade your projects to newer versions. Get used to editing MSBuild files by hand to ensure it doesn't do this, or downgrade what it already did. For the final VSIX you ship to users it's often best to either build with an older version of VS to ensure it's not picking up newer stuff by accident. If you want to only use a newer version, then you'll have to find the VS binaries from the older version you wish to use and check those into your source control system to ensure the older versions are still being picked up. Test your VSIX if you go this route as it's easy to make a mistake and reference something newer by accident.

I wrote an article discussing the various assembly versioning policies used by Visual Studio assemblies.
http://tunnelvisionlabs.github.io/vsbase/docs-master/html/edbfd3ce-43f4-4f3f-a90c-bc22bda19fae.htm
In addition, the VSSDK.* NuGet packages use dependency declarations to help you identify the version(s) of Visual Studio each extension can be used with.
The particular version of Microsoft.VisualStudio.Shell you referenced is a Versioned Assembly (per the previous article) and included in the VSSDK.Shell.12 package, with the following description:
This package provides the Visual Studio "Shell" reference assembly used by Visual Studio 2013 and newer.
To easily target both Visual Studio 2012 and Visual Studio 2013, use NuGet to manage your VS SDK dependencies, and ensure the following conditions hold:
Make sure your assembly does not have a dependency on the VSSDK.IDE.12 NuGet package. This dependency means one or more assemblies referenced by your project only work with Visual Studio 2013 and newer.
Make sure your assembly does not have a dependency on VSSDK.IDE.10Only, VSSDK.IDE.11Only, or VSSDK.IDE.12Only. These indicate that your package references one or more assemblies that only work with a particular version of Visual Studio.
Ideally you would only want to install VSSDK NuGet packages which include both the vs2012 and vs2013 tags.

Related

How to make Visual Studio Setup Project detect nuget dependencies consistent with build?

I created a setup project using Microsoft Visual Studio Installer Projects (0.9.3, this is latest for Visual Studio 2019). After setup is executed it installs Nuget package assemblies that are different from the assemblies generated during build.
Why is it doing that and how can I make it to chose assemblies consistent with build assemblies?
My application is for 4.7.2 framework. Typical example is System.ValueTuple.dll (4.0.2)
Build retrieves assembly from:
C:\Users\.nuget\packages\system.valuetuple\4.5.0\lib\net47\System.ValueTuple.dll
Install retrieves assembly from:
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.7.2\Facades\System.ValueTuple.dll
While install based on 4.0.2 creates a concern but works, when I upgrade nuget package to version 4.6 (and assembly to 4.0.3) install switches to using assembly C:\Users\vgdev.nuget\packages\system.valuetuple\4.5.0\ref\net47\System.ValueTuple.dll
If you look closer, you will notice path above has \ref folder and it contains "reference" assembly. Reference assemblies are not meant to be installed and cause errors BadImageformatException.
The build after Nuget package upgrade continues to pull packages from the correct \lib folder and application works fine. So what I want to do is to make installer work consistently with build. Any advice?
Install retrieves assembly from: C:\Program Files (x86)\Reference
Assemblies\Microsoft\Framework.NETFramework\v4.7.2\Facades\System.ValueTuple.dll
Which way do you reference that package? I can only reproduce this issue when I add reference manually.(Right-click project=>Add reference=>Browse...) If you're doing so, please remove that reference, and add that reference back by Nuget Package Manager UI.
My application is for 4.7.2 framework. Typical example is
System.ValueTuple.dll (4.0.2). When I upgrade nuget package to version 4.6 (and assembly to 4.0.3)
I can only find it with latest 4.5.0 here. And I think it contains the assembly version 4.0.3 instead of 4.0.2.
(I guess something corrupts the process when VS recognize your assembly version cause in most machines it displays 4.0.3 while in one machine, it displays 4.0.2, quite strange...)
The build after Nuget package upgrade continues to pull packages from
the correct \lib folder and application works fine. So what I want to
do is to make installer work consistently with build. Any advice?
Cause of the issue:
This strange behavior may have something to do with Setup project. I can reproduce same situation and I found this issue only occurs when I use PackageReference format to manage nuget packages in my application.(.net 4.7.2)
PackageReference format is the new nuget package manage format after VS2017. I'm not sure if the Setup project fully support for it.
Here're two suggestions which may help:
1.I found this issue only occurs when using PackageReference format. So you can try using Packages.config format in your application. And I've checked the setup project can recognize this format well.
Uninstall all PackageReference format packages, and go Tools=>Nuget Packages Manager=>Nuget Package Manager to set the Allow format selection... to true.
Clean all nuget cache and click ok. After that delete bin and obj folders, then restart VS to add those packages back using Packages.config format.
2.If you continue to use PackageReference format. Try excluding the assembly from ref folder, and manually add that from lib folder by Add=>Assembly=>Browse.
Note: Since Setup project may not fully support packageReference format projects, actually I think #1 could be more suitable for your situation. And you can create a new simple project with packages.config format to check if the issue can be resolved by Packages.config format. Hope it helps :)
It seems that the root cause of the problem is the usage of the BuiltProjectOutputGroupDependencies target by visual studio setup projects instead of the ReferenceCopyLocalPathsOutputGroup target (see PackageReferences put ref instead of lib assemblies in the output group used by VS installer projects).
The proposed workaround is to overwrite the BuiltProjectOutputGroupDependencies target at the end in the project file of your main project:
<Target
Name="BuiltProjectOutputGroupDependencies"
DependsOnTargets="$(BuiltProjectOutputGroupDependenciesDependsOn)"
Returns="#(BuiltProjectOutputGroupDependency)">
<ItemGroup>
<BuiltProjectOutputGroupDependency Include="#(ReferenceCopyLocalPaths->'%(FullPath)');
#(ReferenceDependencyPaths->'%(FullPath)');
#(NativeReferenceFile->'%(FullPath)');
#(_DeploymentLooseManifestFile->'%(FullPath)');
#(ResolvedIsolatedComModules->'%(FullPath)');
#(ReferenceComWrappersToCopyLocal->'%(FullPath)')"/>
</ItemGroup>
</Target>

Can't load EntityFramework.dll 5.0.0.0 inside Visual Studio 2013 extension

I'm writing a Visual Studio extension which depends on EntityFramework 5.0.0.0. I included EntityFramework in my project. When I install my extension, my extension's DLL appears in VS extensions folder, and EntityFramework.dll appears with it as well.
However, when I run my Extension in Visual Studio 2013 (update 5), it can't load EntityFramework: System.IO.FileNotFoundException: Could not load file or assembly 'EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' or one of its dependencies. The system cannot find the file specified.
Looking in Process Monitor, I saw that when I run my extension, VS2013 tries to load EntityFramework from a different path, which has it in a different version - 4.2. I'd expect VS2013 to continue to search for EntityFramework, and find it in my extension's folder, like it does for other dlls included in my extension, but it doesn't.
In VS2015, VS does manage to load EntityFramework 5.0.0.0, but it does so also from yet another different path.
Why doesn't VS2013 continue to search for EntityFramework in my extension's folder?
You need to specify a ProvideCodeBase attribute to specify that your extra assemblies should be loaded. "Sometimes" you get lucky and it finds something else, but that's never guaranteed to work. You can see a few examples of that being used here.

Visual Studio Solution DLL error

I have a visual studio solution which works fine on one machine and when I copy the complete same solution to another machine it misses few external dlls.
Both the machine have same configuration and same version of visual studio.
I tried removing reference and adding again.I am able to reference the dll and use code but when I re-build,It gives the same error.Any pointers on what could have gone wrong?
The error message I get is as below
The type or namespace name 'NameSpaceName" could not be found (are you missing a using directive or an assembly reference?)
Also the warning shows.
The primary reference "NameSpaceName" could not be resolved because it was built against the ".NETFramework,Version=v4.5" framework. This is a higher version than the currently targeted framework ".NETFramework,Version=v4.0".
Both the machine have Visual Studio 2010 installed. It works on one and doesn't work on another machine
The reference you have added to the project is likely not in a subfolder of your project but referenced from the Global Assembly Cache (GAC). Since you probably didn't copy the GAC, this reference is now of a different version. Figure out which (3rd party ?) component is affected and install an older version of that component.
Typically, Visual Studio cannot target .NET 4.5, unless you applied a workaround. In that case, you can go to the project properties, Application and change Target Framework from 4.0 to 4.5.

VSIX dependency based on visual studio version

I had created a visual studio extension (VSIX) which was compatible with vs2010 and vs2012. It had Nuget Package Manager as a dependency. Now I want to make it compatible with vs2013. I added the vs2013 to the supported products. But, the istallation would always fail. Apparently, Nuget team have changed the Identfier for vsix extension for vs2013. I cannot change the identifier to new one as it will affect vs2010/12.
<References>
<Reference Id="NuPackToolsVsix.Microsoft.67e54e40-0ae3-42c5-a949-fddf5739e7a5">
<Name>NuGet Package Manager</Name>
<MoreInfoUrl>http://docs.nuget.org/</MoreInfoUrl>
</Reference>
</References>
Is there a way to add depndencies to vsix based on visual studio version. So that I can add one more reference to nuget for vs2013. OR is there any workaround to this?
The new identifier for vs2013 nuget extension is NuGet.67e54e40-0ae3-42c5-a949-fddf5739e6a5
You can do either of the following:
Remove the reference to the NuGet extension. This will result in a risk of package load errors or other errors if your users do not have NuGet installed, or if they have an outdated version of NuGet that your extension does not support.
Ship separate VSIX packages of your extension for Visual Studio 2010-2012 and Visual Studio 2013.
The latter is likely the best approach. You can create both extensions from the same codebase by following the approach used in the Cloud Explorer extension (note there will be subtle differences because this extension doesn't support Visual Studio 2010, but yours does).
Create a separate project file for the VS2013 extension in the same folder as the extension that targets 2010-2012. I highly recommend you use a visual diff tool to compare Rackspace.VisualStudio.CloudExplorer.11.csproj and Rackspace.VisualStudio.CloudExplorer.12.csproj to show the subtle differences that allow these to live side-by-side.
Create subfolders Properties\vs2010 and Properties\vs2013 to hold the two separate versions of your source.extension.vsixmanifest file. Use the correct NuGet reference for each of these files.
If your project is open source on GitHub, I could help apply the changes and send a pull request.

Issue when migrating CodedUI test from VS2010 to VS2012

I am having some serious issue when migrating Coded UI test from VS2010 to VS2012. The issue is related to assembly reference. I try to reference the new 11.0 version CodedUI assemblies, but the system keeps looking for the old 10.0 version when VS2012 tries to find all the cases and list in the Test Viewer. Such as:
'Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
I found this MSDN link: http://msdn.microsoft.com/en-us/library/tfs/hh506981(v=vs.110).aspx
It mentions some issue related to assemlby reference. But I don't understand the following quotation:
In Visual Studio 2010, references were added inside a ‘Choose’
statement in the csproj file. In Visual Studio 2012, we are using
a Feedback targets file to include Coded UI Test Assembly references.
What is a Feedback targets file??
I've covered your problem with the answer in this blog post.
You need to open your proj file and check for the logic that has been added to reference properly the version 11.0.0.0 of the testing tools assemblies.
I presume the feedback targets file is the imported msbuild file in the VS 2012 folder for msbuild targets. It is an implementation detail, all you need is to focus in upgrading your project file according to what the "repair" wizard is supposed to do, I give precise steps in my post.
Regards and good luck (if I'm not too late)

Resources