Skip to content
This repository has been archived by the owner on Jul 15, 2023. It is now read-only.

Fix Vsixs at Runtime #420

Merged
merged 10 commits into from
May 4, 2017
28 changes: 15 additions & 13 deletions src/ApiPort.VisualStudio/ApiPort.VisualStudio.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
<PropertyGroup>
<MinimumVisualStudioVersion>15.0</MinimumVisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<UseCodebase>true</UseCodebase>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
Expand Down Expand Up @@ -97,28 +96,28 @@
<HintPath>..\..\packages\Microsoft.VisualStudio.OLE.Interop.7.10.6070\lib\Microsoft.VisualStudio.OLE.Interop.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.Shell.15.0, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.VisualStudio.Shell.15.0.15.0.26201\lib\Microsoft.VisualStudio.Shell.15.0.dll</HintPath>
<Reference Include="Microsoft.VisualStudio.Shell.14.0, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.VisualStudio.Shell.14.0.14.3.25407\lib\Microsoft.VisualStudio.Shell.14.0.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.Shell.Framework, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.VisualStudio.Shell.Framework.15.0.26201\lib\net45\Microsoft.VisualStudio.Shell.Framework.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.10.0, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.VisualStudio.Shell.Immutable.10.0.15.0.25413-Preview5\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll</HintPath>
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.10.0, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.VisualStudio.Shell.Immutable.10.0.10.0.30319\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.11.0, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.VisualStudio.Shell.Immutable.11.0.15.0.25413-Preview5\lib\net45\Microsoft.VisualStudio.Shell.Immutable.11.0.dll</HintPath>
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.11.0, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.VisualStudio.Shell.Immutable.11.0.11.0.50727\lib\net45\Microsoft.VisualStudio.Shell.Immutable.11.0.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.12.0, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.VisualStudio.Shell.Immutable.12.0.15.0.25413-Preview5\lib\net45\Microsoft.VisualStudio.Shell.Immutable.12.0.dll</HintPath>
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.12.0, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.VisualStudio.Shell.Immutable.12.0.12.0.21003\lib\net45\Microsoft.VisualStudio.Shell.Immutable.12.0.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.14.0, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.VisualStudio.Shell.Immutable.14.0.15.0.25403-Preview5\lib\net45\Microsoft.VisualStudio.Shell.Immutable.14.0.dll</HintPath>
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.14.0, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.VisualStudio.Shell.Immutable.14.0.14.3.25407\lib\net45\Microsoft.VisualStudio.Shell.Immutable.14.0.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.Shell.Interop, Version=7.1.40304.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
Expand Down Expand Up @@ -199,6 +198,9 @@
<Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
</Reference>
<Reference Include="System.Diagnostics.FileVersionInfo, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll</HintPath>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Globalization.Calendars, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Globalization.Calendars.4.3.0\lib\net46\System.Globalization.Calendars.dll</HintPath>
Expand Down Expand Up @@ -262,6 +264,7 @@
<ItemGroup>
<Compile Include="AnalysisOptions.cs" />
<Compile Include="Analyze\IVsApiPortAnalyzer.cs" />
<Compile Include="AssemblyRedirectResolver.cs" />
<Compile Include="Properties\Properties.cs" />
<Compile Include="Reporting\IResultToolbar.cs" />
<Compile Include="Reporting\ToolbarListReportViewer.cs" />
Expand Down Expand Up @@ -340,7 +343,6 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<IncludeInVSIX>true</IncludeInVSIX>
</Content>
<None Include="app.config" />
<None Include="packages.config" />
<None Include="source.extension.vsixmanifest">
<SubType>Designer</SubType>
Expand Down
12 changes: 12 additions & 0 deletions src/ApiPort.VisualStudio/ApiPortVSPackage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,27 @@ namespace ApiPortVS
public class ApiPortVSPackage : Package, IResultToolbar
{
private static ServiceProvider s_serviceProvider;
private readonly AssemblyRedirectResolver _assemblyResolver;

internal static IServiceProvider LocalServiceProvider { get { return s_serviceProvider; } }

public ApiPortVSPackage() : base()
{
s_serviceProvider = new ServiceProvider(this);
_assemblyResolver = s_serviceProvider.GetService(typeof(AssemblyRedirectResolver)) as AssemblyRedirectResolver;

if (_assemblyResolver == default(AssemblyRedirectResolver))
{
throw new InvalidOperationException("Could not find AssemblyRedirectResolver. It should have been resolved in the service provider.");
}

AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}

protected override void Dispose(bool disposing)
{
s_serviceProvider.Dispose();
AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomain_AssemblyResolve;

base.Dispose(disposing);
}
Expand Down Expand Up @@ -102,6 +112,8 @@ public void ShowToolbar()
ErrorHandler.ThrowOnFailure(windowFrame.Show());
}

private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) => _assemblyResolver.ResolveAssembly(args.Name, args.RequestingAssembly);

private void ShowOptionsPage(object sender, EventArgs e)
{
ShowOptionPage(typeof(OptionsPage));
Expand Down
102 changes: 102 additions & 0 deletions src/ApiPort.VisualStudio/AssemblyRedirectResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;

namespace ApiPortVS
{
/// <summary>
/// Because the VSIX runs inside devenv.exe, the only configuration file that is used for redirects is
/// devenv.exe.config.We don't want to modify this machine wide configuration so we are manually setting
/// the redirects.
/// More info: http://stackoverflow.com/a/31248093/4220757
/// </summary>
internal class AssemblyRedirectResolver
{
private readonly IEnumerable<AssemblyRedirect> _redirects;
private readonly IDictionary<string, AssemblyRedirect> _redirectsDictionary;

public AssemblyRedirectResolver(string configFile)
{
var xml = XDocument.Load(configFile);
Func<string, XName> getFullName = (name) => { return XName.Get(name, "urn:schemas-microsoft-com:asm.v1"); };

var redirects = from element in xml.Descendants(getFullName("dependentAssembly"))
let identity = element.Element(getFullName("assemblyIdentity"))
let redirect = element.Element(getFullName("bindingRedirect"))
let name = identity.Attribute("name").Value
let publicKey = identity.Attribute("publicKeyToken").Value
let newVersion = redirect.Attribute("newVersion").Value
select new AssemblyRedirect(name, newVersion, publicKey);

_redirects = redirects;
_redirectsDictionary = redirects.ToDictionary(x => x.Name);
}

public AssemblyRedirectResolver(DirectoryInfo assemblyFolder)
{
_redirects = assemblyFolder.GetFiles("*.dll")
.Select(dll => {
var name = AssemblyName.GetAssemblyName(dll.FullName);
var publicKeyToken = name.GetPublicKeyToken().Aggregate("", (s, b) => s += b.ToString("x2"));
return new AssemblyRedirect(name.Name, name.Version.ToString(), publicKeyToken);
});

_redirectsDictionary = _redirects.ToDictionary(x => x.Name);
}

public Assembly ResolveAssembly(string assemblyName, Assembly requestingAssembly)
{
// Use latest strong name & version when trying to load SDK assemblies
var requestedAssembly = new AssemblyName(assemblyName);

AssemblyRedirect redirectInformation;

if (!_redirectsDictionary.TryGetValue(requestedAssembly.Name, out redirectInformation))
{
return null;
}

Trace.WriteLine("Redirecting assembly load of " + assemblyName
+ ",\tloaded by " + (requestingAssembly == null ? "(unknown)" : requestingAssembly.FullName));

var alreadyLoadedAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a =>
{
var assm = a.GetName();
return string.Equals(assm.Name, requestedAssembly.Name, StringComparison.Ordinal)
&& redirectInformation.TargetVersion.Equals(assm.Version);
});

if (alreadyLoadedAssembly != default(Assembly))
{
return alreadyLoadedAssembly;
}

requestedAssembly.Version = redirectInformation.TargetVersion;
requestedAssembly.SetPublicKeyToken(new AssemblyName("x, PublicKeyToken=" + redirectInformation.PublicKeyToken).GetPublicKeyToken());
requestedAssembly.CultureInfo = CultureInfo.InvariantCulture;

return Assembly.Load(requestedAssembly);
}
}

internal class AssemblyRedirect
{
public readonly string Name;

public readonly string PublicKeyToken;

public readonly Version TargetVersion;

public AssemblyRedirect(string name, string version, string publicKeyToken)
{
Name = name;
TargetVersion = new Version(version);
PublicKeyToken = publicKeyToken;
}
}
}
4 changes: 3 additions & 1 deletion src/ApiPort.VisualStudio/ServiceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace ApiPortVS
internal sealed class ServiceProvider : IDisposable, IServiceProvider
{
private static Guid OutputWindowGuid = new Guid(0xe2fc797f, 0x1dd3, 0x476c, 0x89, 0x17, 0x86, 0xcd, 0x31, 0x33, 0xc4, 0x69);

private static readonly DirectoryInfo AssemblyDirectory = new FileInfo(typeof(ServiceProvider).Assembly.Location).Directory;
private const string DefaultEndpoint = @"https://portability.dot.net/";

private readonly IContainer _container;
Expand Down Expand Up @@ -61,6 +61,8 @@ public ServiceProvider(ApiPortVSPackage serviceProvider)
// Service registration
builder.RegisterInstance(new ProductInformation("ApiPort_VS"))
.AsSelf();
builder.RegisterInstance(new AssemblyRedirectResolver(AssemblyDirectory))
.AsSelf();
builder.RegisterType<ApiPortService>().
As<IApiPortService>().
WithParameter(TypedParameter.From<string>(DefaultEndpoint))
Expand Down
3 changes: 2 additions & 1 deletion src/ApiPort.VisualStudio/Views/OptionsPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ private System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender,

protected override void Dispose(bool disposing)
{
_optionsPageControl.Dispose();
if (_optionsPageControl != null)
_optionsPageControl.Dispose();

base.Dispose(disposing);
}
Expand Down
27 changes: 0 additions & 27 deletions src/ApiPort.VisualStudio/app.config

This file was deleted.

11 changes: 6 additions & 5 deletions src/ApiPort.VisualStudio/packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
<package id="Microsoft.VisualStudio.Imaging" version="15.0.26201" targetFramework="net46" />
<package id="Microsoft.VisualStudio.OLE.Interop" version="7.10.6070" targetFramework="net46" />
<package id="Microsoft.VisualStudio.SDK.EmbedInteropTypes" version="15.0.4" targetFramework="net46" />
<package id="Microsoft.VisualStudio.Shell.15.0" version="15.0.26201" targetFramework="net46" />
<package id="Microsoft.VisualStudio.Shell.14.0" version="14.3.25407" targetFramework="net46" />
<package id="Microsoft.VisualStudio.Shell.Framework" version="15.0.26201" targetFramework="net46" />
<package id="Microsoft.VisualStudio.Shell.Immutable.10.0" version="15.0.25413-Preview5" targetFramework="net46" />
<package id="Microsoft.VisualStudio.Shell.Immutable.11.0" version="15.0.25413-Preview5" targetFramework="net46" />
<package id="Microsoft.VisualStudio.Shell.Immutable.12.0" version="15.0.25413-Preview5" targetFramework="net46" />
<package id="Microsoft.VisualStudio.Shell.Immutable.14.0" version="15.0.25403-Preview5" targetFramework="net46" />
<package id="Microsoft.VisualStudio.Shell.Immutable.10.0" version="10.0.30319" targetFramework="net46" />
<package id="Microsoft.VisualStudio.Shell.Immutable.11.0" version="11.0.50727" targetFramework="net46" />
<package id="Microsoft.VisualStudio.Shell.Immutable.12.0" version="12.0.21003" targetFramework="net46" />
<package id="Microsoft.VisualStudio.Shell.Immutable.14.0" version="14.3.25407" targetFramework="net46" />
<package id="Microsoft.VisualStudio.Shell.Interop" version="7.10.6071" targetFramework="net46" />
<package id="Microsoft.VisualStudio.Shell.Interop.10.0" version="10.0.30319" targetFramework="net46" />
<package id="Microsoft.VisualStudio.Shell.Interop.11.0" version="11.0.61030" targetFramework="net46" />
Expand All @@ -44,6 +44,7 @@
<package id="System.Diagnostics.Contracts" version="4.3.0" targetFramework="net46" />
<package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net46" />
<package id="System.Diagnostics.DiagnosticSource" version="4.3.0" targetFramework="net46" />
<package id="System.Diagnostics.FileVersionInfo" version="4.3.0" targetFramework="net46" />
<package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net46" />
<package id="System.Diagnostics.Tracing" version="4.3.0" targetFramework="net46" />
<package id="System.Globalization" version="4.3.0" targetFramework="net46" />
Expand Down
2 changes: 1 addition & 1 deletion src/ApiPort.Vsix/ApiPort.Vsix.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<DeployExtension>True</DeployExtension>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
Expand All @@ -52,7 +53,6 @@
<IsPackage>true</IsPackage>
</PropertyGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
<None Include="source.extension.vsixmanifest">
<SubType>Designer</SubType>
Expand Down
27 changes: 0 additions & 27 deletions src/ApiPort.Vsix/app.config

This file was deleted.

Loading