Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Microsoft.VisualStudio.Composition/PartDiscovery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public Task<DiscoveredParts> CreatePartsAsync(params Type[] partTypes)
{
try
{
return new Assembly[] { this.Resolver.AssemblyLoader.LoadAssembly(Utilities.GetAssemblyNameWithCodebasePath(path)) };
return new Assembly[] { this.Resolver.AssemblyLoader.LoadAssembly(AssemblyName.GetAssemblyName(path).FullName, path) };
}
catch (Exception ex)
{
Expand Down
24 changes: 23 additions & 1 deletion src/Microsoft.VisualStudio.Composition/StandardAssemblyLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@

namespace Microsoft.VisualStudio.Composition
{
using System;
using System.Collections.Generic;
using System.Reflection;
#if NET
using System.Runtime.Loader;
#endif

/// <summary>
/// A typical .NET Framework implementation of the <see cref="IAssemblyLoader"/> interface.
Expand Down Expand Up @@ -48,6 +50,26 @@ public Assembly LoadAssembly(string assemblyFullName, string? codeBasePath)
if (!string.IsNullOrEmpty(codeBasePath))
{
assemblyName.CodeBase = codeBasePath;

#if NET
// On Core CLR, Assembly.Load(AssemblyName) doesn't respect the CodeBase property,
// so we have to use AssemblyLoadContext.LoadFromAssemblyPath instead.
// But we'll only resort to that if the ALC doesn't already have a preferred location from which to load the assembly.
try
{
return this.LoadAssembly(assemblyName);
}
catch
{
// Now that the ALC failed to find the assembly, try to load it from the code base path.
AssemblyLoadContext alc = AssemblyLoadContext.CurrentContextualReflectionContext ?? AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly())!;
Assembly assembly = alc.LoadFromAssemblyPath(codeBasePath);
lock (this.loadedAssemblies)
{
this.loadedAssemblies[assemblyName] = assembly;
}
}
#endif
}

return this.LoadAssembly(assemblyName);
Expand Down
16 changes: 0 additions & 16 deletions src/Microsoft.VisualStudio.Composition/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,6 @@ internal static class Utilities
{
private const string CompositionErrorHeaderFormat = "----- CompositionError level {0} ------";

/// <summary>
/// Creates an <see cref="AssemblyName"/> that is guaranteed to have its <see cref="AssemblyName.CodeBase"/> property set.
/// </summary>
/// <param name="path">The path to the assembly to get the name for.</param>
/// <returns>An initialized <see cref="AssemblyName"/> instance.</returns>
internal static AssemblyName GetAssemblyNameWithCodebasePath(string path)
{
AssemblyName assemblyName = AssemblyName.GetAssemblyName(path);

// .NET Framework sets this, but .NET Core does not.
// .NET Core also *ignores* this even if set, by default. But a custom AssemblyLoadContext resolver could honor it if we preserve it.
assemblyName.CodeBase = path;

return assemblyName;
}

internal static void WriteErrors(TextWriter textWriter, IImmutableStack<IReadOnlyCollection<ComposedPartDiagnostic>> errorStack)
{
int level = 1;
Expand Down