Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Synchronize razor compiler assembly loading #11394

Merged
merged 11 commits into from
Jan 23, 2025
48 changes: 48 additions & 0 deletions docs/AssemblyLoadingStrategy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Assembly Loading Strategy

When running in co-hosting mode it is essential that the types used by the source generator and the rest of the tooling unify; Roslyn and Razor tooling must 'share' the same loaded copy of the source generator. This requires that Roslyn and Razor co-ordinate as to who is responsible for loading the source generator, and the other party must use the already loaded copy. Unfortunately, due to asynchronous loading it is non-deterministic as to which party will first attempt to load the generator.

In order to synchronize the loading, Razor tooling always defers loading the Razor compiler to Roslyn via the ExternalAccess (EA) assembly. Roslyn will load the Razor compiler assembly, and its dependencies, into a shared ALC. If the Razor tooling accesses the generator before Roslyn has loaded it, it will first be loaded then returned. When Roslyn comes to load the generator the already existing copy will be used to ensure it remains shared.

Note that this strategy requires the Roslyn EA loader stub to know the name of the Razor compiler assembly and its dependencies. This is not ideal, but removes the need for extremely complicated synchronization code between the two processes. It is assumed that the compiler name and its dependencies wil change a small enough amount of times for this to be a fair trade off.

## Intercepting the ALC load for Razor tooling

In order to 'choose' which source generator assembly is used by the tooling, it needs some method to intercept the loading of the assembly and return the preferred copy. Razor tooling is hosted in ServiceHub, which has its own assembly loading mechanisms based on ALC. Unfortunately there is no way to override the loading logic of the provided ALC that can be hooked into to achieve this. Instead, Razor provides its own ALC ([RazorAssemblyLoadContext.cs](..\src\Razor\src\Microsoft.CodeAnalysis.Remote.Razor\RazorAssemblyLoadContext.cs)) that has the logic required to interact with the Roslyn EA assembly.

ServiceHub doesn't provide a way to specify a particular ALC implementation to use when loading a service, and due to the nature of ServiceHub by the time the razor tooling code is running it has already been loaded into the ServiceHub ALC. Thus Razor tooling needs a way of bootstrapping itself into the Razor specific ALC before any code runs.

This is handled in [RazorBrokeredServiceBase.FactoryBase\`1.cs](..\src\Razor\src\Microsoft.CodeAnalysis.Remote.Razor\RazorBrokeredServiceBase.FactoryBase`1.cs). When ServiceHub requests the factory create an instance of the service, the factory instead loads a copy of itself into a shared instance of the `RazorAssemblyLoadContext`, and via reflection thunks the create request to the factory there. The instance created in the Razor ALC is returned to ServiceHub. This means that any code in the returned service that causes as assembly load will be handled by the Razor ALC, allowing for interception in the case of the source generator.

### Example

```mermaid
sequenceDiagram
box ServiceHub ALC
participant serviceHub as Service Hub
participant factory(1) as Factory
end
box Razor ALC
participant razorAlc as RazorAssemblyLoadContext
participant factory(2) as Factory
participant serviceInstance as Service Instance
end

serviceHub->>factory(1): Create Service
factory(1)->>razorAlc: Load self
#create participant factory(2) as Factory
#(see https://github.com/mermaid-js/mermaid/issues/5023)
factory(1)->>factory(2): Create New Factory
factory(2)-->>factory(1):
factory(1)->>factory(2): Create Service Internal
#create participant serviceInstance as Service Instance
factory(2)->>serviceInstance: Create Service instance
serviceInstance-->>serviceHub: Return instance
serviceHub->>serviceHub: Wait for request
serviceHub->>serviceInstance: Handle Request
serviceInstance-->>razorAlc: Implicit load request
razorAlc->>razorAlc: Load source generator
razorAlc-->>serviceInstance:
serviceInstance->>serviceInstance: Handle Request
serviceInstance-->>serviceHub: Result
```
76 changes: 38 additions & 38 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,82 +11,82 @@
<Sha>1d0bf118044fc096231bfba85b0cd68aad0d1507</Sha>
<SourceBuild RepoName="source-build-reference-packages" ManagedOnly="true" />
</Dependency>
<Dependency Name="Microsoft.Net.Compilers.Toolset" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.Net.Compilers.Toolset" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CommonLanguageServerProtocol.Framework" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CommonLanguageServerProtocol.Framework" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.ExternalAccess.Razor" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CodeAnalysis.ExternalAccess.Razor" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.Common" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CodeAnalysis.Common" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.CSharp" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CodeAnalysis.CSharp" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.CSharp.EditorFeatures" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CodeAnalysis.CSharp.EditorFeatures" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.CSharp.Features" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CodeAnalysis.CSharp.Features" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.EditorFeatures" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CodeAnalysis.EditorFeatures" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.EditorFeatures.Common" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CodeAnalysis.EditorFeatures.Common" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.EditorFeatures.Text" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CodeAnalysis.EditorFeatures.Text" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.EditorFeatures.Wpf" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CodeAnalysis.EditorFeatures.Wpf" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.Remote.ServiceHub" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CodeAnalysis.Remote.ServiceHub" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CodeAnalysis.VisualBasic.Workspaces" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.VisualStudio.LanguageServices" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.VisualStudio.LanguageServices" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<Dependency Name="Microsoft.CodeAnalysis.Test.Utilities" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.CodeAnalysis.Test.Utilities" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
</Dependency>
<!-- Intermediate is necessary for source build. -->
<Dependency Name="Microsoft.SourceBuild.Intermediate.roslyn" Version="4.13.0-3.25057.3">
<Dependency Name="Microsoft.SourceBuild.Intermediate.roslyn" Version="4.14.0-1.25071.1">
<Uri>https://github.com/dotnet/roslyn</Uri>
<Sha>911cf5f462960bdd01df1ea3c0d0c217b3c3838b</Sha>
<Sha>5970c1a8588cc6bac346d9ad3eebb41321713ab0</Sha>
<SourceBuild RepoName="roslyn" ManagedOnly="true" />
</Dependency>
</ProductDependencies>
Expand Down
38 changes: 19 additions & 19 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -53,25 +53,25 @@
<MicrosoftSourceBuildIntermediatearcadePackageVersion>9.0.0-beta.24572.2</MicrosoftSourceBuildIntermediatearcadePackageVersion>
<MicrosoftDotNetXliffTasksPackageVersion>1.0.0-beta.23475.1</MicrosoftDotNetXliffTasksPackageVersion>
<MicrosoftSourceBuildIntermediatexlifftasksPackageVersion>1.0.0-beta.23475.1</MicrosoftSourceBuildIntermediatexlifftasksPackageVersion>
<MicrosoftNetCompilersToolsetPackageVersion>4.13.0-3.25057.3</MicrosoftNetCompilersToolsetPackageVersion>
<MicrosoftCommonLanguageServerProtocolFrameworkPackageVersion>4.13.0-3.25057.3</MicrosoftCommonLanguageServerProtocolFrameworkPackageVersion>
<MicrosoftCodeAnalysisExternalAccessRazorPackageVersion>4.13.0-3.25057.3</MicrosoftCodeAnalysisExternalAccessRazorPackageVersion>
<MicrosoftCodeAnalysisCommonPackageVersion>4.13.0-3.25057.3</MicrosoftCodeAnalysisCommonPackageVersion>
<MicrosoftCodeAnalysisCSharpPackageVersion>4.13.0-3.25057.3</MicrosoftCodeAnalysisCSharpPackageVersion>
<MicrosoftCodeAnalysisCSharpEditorFeaturesPackageVersion>4.13.0-3.25057.3</MicrosoftCodeAnalysisCSharpEditorFeaturesPackageVersion>
<MicrosoftCodeAnalysisCSharpFeaturesPackageVersion>4.13.0-3.25057.3</MicrosoftCodeAnalysisCSharpFeaturesPackageVersion>
<MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>4.13.0-3.25057.3</MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>
<MicrosoftCodeAnalysisEditorFeaturesPackageVersion>4.13.0-3.25057.3</MicrosoftCodeAnalysisEditorFeaturesPackageVersion>
<MicrosoftCodeAnalysisEditorFeaturesCommonPackageVersion>4.13.0-3.25057.3</MicrosoftCodeAnalysisEditorFeaturesCommonPackageVersion>
<MicrosoftCodeAnalysisEditorFeaturesTextPackageVersion>4.13.0-3.25057.3</MicrosoftCodeAnalysisEditorFeaturesTextPackageVersion>
<MicrosoftCodeAnalysisEditorFeaturesWpfPackageVersion>4.13.0-3.25057.3</MicrosoftCodeAnalysisEditorFeaturesWpfPackageVersion>
<MicrosoftCodeAnalysisRemoteServiceHubPackageVersion>4.13.0-3.25057.3</MicrosoftCodeAnalysisRemoteServiceHubPackageVersion>
<MicrosoftCodeAnalysisTestUtilitiesPackageVersion>4.13.0-3.25057.3</MicrosoftCodeAnalysisTestUtilitiesPackageVersion>
<MicrosoftCodeAnalysisVisualBasicWorkspacesPackageVersion>4.13.0-3.25057.3</MicrosoftCodeAnalysisVisualBasicWorkspacesPackageVersion>
<MicrosoftCodeAnalysisWorkspacesCommonPackageVersion>4.13.0-3.25057.3</MicrosoftCodeAnalysisWorkspacesCommonPackageVersion>
<MicrosoftCodeAnalysisWorkspacesMSBuildPackageVersion>4.13.0-3.25057.3</MicrosoftCodeAnalysisWorkspacesMSBuildPackageVersion>
<MicrosoftSourceBuildIntermediateroslynPackageVersion>4.13.0-3.25057.3</MicrosoftSourceBuildIntermediateroslynPackageVersion>
<MicrosoftVisualStudioLanguageServicesPackageVersion>4.13.0-3.25057.3</MicrosoftVisualStudioLanguageServicesPackageVersion>
<MicrosoftNetCompilersToolsetPackageVersion>4.14.0-1.25071.1</MicrosoftNetCompilersToolsetPackageVersion>
<MicrosoftCommonLanguageServerProtocolFrameworkPackageVersion>4.14.0-1.25071.1</MicrosoftCommonLanguageServerProtocolFrameworkPackageVersion>
<MicrosoftCodeAnalysisExternalAccessRazorPackageVersion>4.14.0-1.25071.1</MicrosoftCodeAnalysisExternalAccessRazorPackageVersion>
<MicrosoftCodeAnalysisCommonPackageVersion>4.14.0-1.25071.1</MicrosoftCodeAnalysisCommonPackageVersion>
<MicrosoftCodeAnalysisCSharpPackageVersion>4.14.0-1.25071.1</MicrosoftCodeAnalysisCSharpPackageVersion>
<MicrosoftCodeAnalysisCSharpEditorFeaturesPackageVersion>4.14.0-1.25071.1</MicrosoftCodeAnalysisCSharpEditorFeaturesPackageVersion>
<MicrosoftCodeAnalysisCSharpFeaturesPackageVersion>4.14.0-1.25071.1</MicrosoftCodeAnalysisCSharpFeaturesPackageVersion>
<MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>4.14.0-1.25071.1</MicrosoftCodeAnalysisCSharpWorkspacesPackageVersion>
<MicrosoftCodeAnalysisEditorFeaturesPackageVersion>4.14.0-1.25071.1</MicrosoftCodeAnalysisEditorFeaturesPackageVersion>
<MicrosoftCodeAnalysisEditorFeaturesCommonPackageVersion>4.14.0-1.25071.1</MicrosoftCodeAnalysisEditorFeaturesCommonPackageVersion>
<MicrosoftCodeAnalysisEditorFeaturesTextPackageVersion>4.14.0-1.25071.1</MicrosoftCodeAnalysisEditorFeaturesTextPackageVersion>
<MicrosoftCodeAnalysisEditorFeaturesWpfPackageVersion>4.14.0-1.25071.1</MicrosoftCodeAnalysisEditorFeaturesWpfPackageVersion>
<MicrosoftCodeAnalysisRemoteServiceHubPackageVersion>4.14.0-1.25071.1</MicrosoftCodeAnalysisRemoteServiceHubPackageVersion>
<MicrosoftCodeAnalysisTestUtilitiesPackageVersion>4.14.0-1.25071.1</MicrosoftCodeAnalysisTestUtilitiesPackageVersion>
<MicrosoftCodeAnalysisVisualBasicWorkspacesPackageVersion>4.14.0-1.25071.1</MicrosoftCodeAnalysisVisualBasicWorkspacesPackageVersion>
<MicrosoftCodeAnalysisWorkspacesCommonPackageVersion>4.14.0-1.25071.1</MicrosoftCodeAnalysisWorkspacesCommonPackageVersion>
<MicrosoftCodeAnalysisWorkspacesMSBuildPackageVersion>4.14.0-1.25071.1</MicrosoftCodeAnalysisWorkspacesMSBuildPackageVersion>
<MicrosoftSourceBuildIntermediateroslynPackageVersion>4.14.0-1.25071.1</MicrosoftSourceBuildIntermediateroslynPackageVersion>
<MicrosoftVisualStudioLanguageServicesPackageVersion>4.14.0-1.25071.1</MicrosoftVisualStudioLanguageServicesPackageVersion>
<!--
Exception - Microsoft.Extensions.ObjectPool and System.Collections.Immutable packages are not updated by automation,
but are present in Version.Details.xml for source-build PVP flow. See the comment in Version.Details.xml for more information.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,4 @@ public static bool TryGetCSharpDocument(this Project project, Uri csharpDocument

return document is not null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ private async ValueTask<Response> TryResolveInsertionAsync(
mappedPosition,
character,
options,
cancellationToken);
cancellationToken)
.ConfigureAwait(false);
default:
Logger.LogError($"Unsupported language {languageKind} in {nameof(RemoteAutoInsertService)}");
return Response.NoFurtherHandling;
Expand Down Expand Up @@ -146,7 +147,7 @@ private async ValueTask<Response> TryResolveInsertionInCSharpAsync(
character,
options.FormattingOptions.ToRoslynFormattingOptions(),
cancellationToken
);
).ConfigureAwait(false);

if (autoInsertResponseItem is null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ private async ValueTask<ImmutableArray<LspDiagnostic>> GetDiagnosticsAsync(

return [
.. RazorDiagnosticConverter.Convert(razorDiagnostics, codeDocument.Source.Text, context.Snapshot),
.. await _translateDiagnosticsService.TranslateAsync(RazorLanguageKind.CSharp, csharpDiagnostics, context.Snapshot, cancellationToken),
.. await _translateDiagnosticsService.TranslateAsync(RazorLanguageKind.Html, htmlDiagnostics, context.Snapshot, cancellationToken)
.. await _translateDiagnosticsService.TranslateAsync(RazorLanguageKind.CSharp, csharpDiagnostics, context.Snapshot, cancellationToken).ConfigureAwait(false),
.. await _translateDiagnosticsService.TranslateAsync(RazorLanguageKind.Html, htmlDiagnostics, context.Snapshot, cancellationToken).ConfigureAwait(false)
];
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);netstandard2.0</TargetFrameworks>
<Description>Razor is a markup syntax for adding server-side logic to web pages. This package contains the Razor design-time infrastructure.</Description>
<EnableApiCheck>false</EnableApiCheck>
<IsShippingPackage>false</IsShippingPackage>
Expand Down
Loading
Loading