Skip to content

Commit 0dcd8f5

Browse files
chsienkijjonesczjaredpar
authored
Razor EA: load from ServiceHubCore (#77720)
* Razor EA: load from ServiceHubCore * Update src/Tools/ExternalAccess/Razor/RazorAnalyzerAssemblyResolver.cs Co-authored-by: Jan Jones <[email protected]> * Trim trailing slashes * Update src/Tools/ExternalAccess/Razor/RazorAnalyzerAssemblyResolver.cs Co-authored-by: Jan Jones <[email protected]> * Fix trim call * PR feedback --------- Co-authored-by: Jan Jones <[email protected]> Co-authored-by: Jared Parsons <[email protected]>
1 parent 4c7017f commit 0dcd8f5

File tree

2 files changed

+48
-0
lines changed

2 files changed

+48
-0
lines changed

src/Tools/ExternalAccess/Razor/EditorFeatures/RazorAnalyzerAssemblyResolver.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ internal sealed class RazorAnalyzerAssemblyResolver() : IAnalyzerAssemblyResolve
2525
public const string RazorUtilsAssemblyName = "Microsoft.AspNetCore.Razor.Utilities.Shared";
2626
public const string ObjectPoolAssemblyName = "Microsoft.Extensions.ObjectPool";
2727

28+
internal const string ServiceHubCoreFolderName = "ServiceHubCore";
29+
2830
internal static readonly ImmutableArray<string> RazorAssemblyNames = [RazorCompilerAssemblyName, RazorUtilsAssemblyName, ObjectPoolAssemblyName];
2931

3032
public Assembly? Resolve(AnalyzerAssemblyLoader loader, AssemblyName assemblyName, AssemblyLoadContext directoryContext, string directory) =>
@@ -54,6 +56,16 @@ internal sealed class RazorAnalyzerAssemblyResolver() : IAnalyzerAssemblyResolve
5456
}
5557

5658
var assemblyFileName = $"{assemblyName.Name}.dll";
59+
60+
// Depending on who wins the race to load these assemblies, the base directory will either be the tooling root (if Roslyn wins)
61+
// or the ServiceHubCore subfolder (razor). In the root directory these are netstandard2.0 targeted, in ServiceHubCore they are
62+
// .net targeted. We need to always pick the same set of assemblies regardless of who causes us to load. Because this code only
63+
// runs in a .net based host, it's safe to always choose the .net targeted ServiceHubCore versions.
64+
if (!Path.GetFileName(directory.AsSpan().TrimEnd(Path.DirectorySeparatorChar)).Equals(ServiceHubCoreFolderName, StringComparison.OrdinalIgnoreCase))
65+
{
66+
directory = Path.Combine(directory, ServiceHubCoreFolderName);
67+
}
68+
5769
var assemblyPath = Path.Combine(directory, assemblyFileName);
5870
if (File.Exists(assemblyPath))
5971
{

src/Tools/ExternalAccess/RazorTest/RazorAnalyzerAssemblyResolverTests.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public void Dispose()
4040

4141
private void CreateRazorAssemblies(string directory, string versionNumber = "1.0.0.0")
4242
{
43+
_ = Directory.CreateDirectory(directory);
4344
foreach (var simpleName in RazorAnalyzerAssemblyResolver.RazorAssemblyNames)
4445
{
4546
BuildOne(simpleName);
@@ -149,5 +150,40 @@ public void FirstLoadWins()
149150
Assert.Same(assembly1, assembly2);
150151
});
151152
}
153+
154+
[Fact]
155+
public void ChooseServiceHubFolder()
156+
{
157+
var dir = TempRoot.CreateDirectory().Path;
158+
CreateRazorAssemblies(dir);
159+
var serviceHubFolder = Path.Combine(dir, RazorAnalyzerAssemblyResolver.ServiceHubCoreFolderName);
160+
CreateRazorAssemblies(serviceHubFolder);
161+
162+
coreTest(dir, serviceHubFolder);
163+
coreTest(dir + Path.DirectorySeparatorChar, serviceHubFolder);
164+
coreTest(serviceHubFolder, serviceHubFolder);
165+
coreTest(serviceHubFolder + Path.DirectorySeparatorChar, serviceHubFolder);
166+
167+
void coreTest(string loadDir, string serviceHubDir)
168+
{
169+
var name = Path.GetFileName(loadDir.AsSpan());
170+
RunWithLoader((resolver, loader, currentLoadContext) =>
171+
{
172+
var assembly1 = resolver.Resolve(
173+
loader,
174+
new AssemblyName(RazorAnalyzerAssemblyResolver.RazorCompilerAssemblyName),
175+
currentLoadContext,
176+
loadDir);
177+
var assembly2 = resolver.Resolve(
178+
loader,
179+
new AssemblyName(RazorAnalyzerAssemblyResolver.RazorCompilerAssemblyName),
180+
currentLoadContext,
181+
serviceHubFolder);
182+
Assert.NotNull(assembly1);
183+
Assert.Same(assembly1, assembly2);
184+
Assert.Equal(serviceHubFolder, Path.GetDirectoryName(assembly1.Location));
185+
});
186+
}
187+
}
152188
}
153189
#endif

0 commit comments

Comments
 (0)