|
| 1 | +// Copyright (c) .NET Foundation. All rights reserved. |
| 2 | +// Licensed under the MIT license. See License.txt in the project root for license information. |
| 3 | + |
| 4 | +using System; |
| 5 | +using System.Collections.Immutable; |
| 6 | +using System.IO; |
| 7 | +using System.Reflection; |
| 8 | +using System.Composition; |
| 9 | +using IRazorAnalyzerAssemblyRedirector = Microsoft.CodeAnalysis.ExternalAccess.Razor.RazorAnalyzerAssemblyRedirector.IRazorAnalyzerAssemblyRedirector; |
| 10 | + |
| 11 | +namespace Microsoft.VisualStudio.Razor; |
| 12 | + |
| 13 | +#pragma warning disable RS0030 // Do not use banned APIs |
| 14 | +[Shared] |
| 15 | +[Export(typeof(IRazorAnalyzerAssemblyRedirector))] |
| 16 | +[method: ImportingConstructor] |
| 17 | +#pragma warning restore RS0030 // Do not use banned APIs |
| 18 | +internal class RazorAnalyzerAssemblyRedirector() : IRazorAnalyzerAssemblyRedirector |
| 19 | +{ |
| 20 | + private static readonly ImmutableArray<Type> s_compilerAssemblyTypes = [ |
| 21 | + |
| 22 | + typeof(CodeAnalysis.Razor.CompilerFeatures), // Microsoft.CodeAnalysis.Razor.Compiler.dll |
| 23 | + typeof(AspNetCore.Razor.ArgHelper), // Microsoft.AspNetCore.Razor.Utilities.Shared.dll |
| 24 | + |
| 25 | + // The following dependencies will be provided by the Compiler ALC so its not strictly required to redirect them, but we do so for completeness. |
| 26 | + typeof(Microsoft.Extensions.ObjectPool.ObjectPool), // Microsoft.Extensions.ObjectPool.dll |
| 27 | + typeof(ImmutableArray) // System.Collections.Immutable.dll |
| 28 | + ]; |
| 29 | + |
| 30 | + private static readonly ImmutableDictionary<string, string> s_compilerAssemblyMap = s_compilerAssemblyTypes.ToImmutableDictionary(t => t.Assembly.GetName().Name!, t => GetAssemblyLocation(t.Assembly)); |
| 31 | + |
| 32 | + public string? RedirectPath(string fullPath) |
| 33 | + { |
| 34 | + var name = Path.GetFileNameWithoutExtension(fullPath); |
| 35 | + return s_compilerAssemblyMap.TryGetValue(name, out var path) ? path : null; |
| 36 | + } |
| 37 | + |
| 38 | + private static string GetAssemblyLocation(Assembly assembly) |
| 39 | + { |
| 40 | + var location = assembly.Location; |
| 41 | + var name = Path.GetFileName(location); |
| 42 | + var directory = Path.GetDirectoryName(location) ?? ""; |
| 43 | + |
| 44 | + // In VS on windows, depending on who wins the race to load these assemblies, the base directory will either be the tooling root (if Roslyn wins) |
| 45 | + // or the ServiceHubCore subfolder (razor). In the root directory these are netstandard2.0 targeted, in ServiceHubCore they are .NET targeted. |
| 46 | + // We need to always pick the same set of assemblies regardless of who causes us to load. Because this code only runs in a .NET based host, |
| 47 | + // we want to prefer the .NET targeted ServiceHubCore versions if they exist. |
| 48 | + var serviceHubCoreVersion = Path.Combine(directory, "ServiceHubCore", name); |
| 49 | + if (File.Exists(serviceHubCoreVersion)) |
| 50 | + { |
| 51 | + return serviceHubCoreVersion; |
| 52 | + } |
| 53 | + |
| 54 | + return location; |
| 55 | + } |
| 56 | +} |
0 commit comments