diff --git a/Razor.sln b/Razor.sln
index fe6f4f71aaa..046867b2eb8 100644
--- a/Razor.sln
+++ b/Razor.sln
@@ -142,6 +142,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.CodeAnalysis.Razo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Razor.Compiler", "src\Compiler\Microsoft.CodeAnalysis.Razor.Compiler\src\Microsoft.CodeAnalysis.Razor.Compiler.csproj", "{E102632D-EC30-474F-B2EB-6EB07ED45F27}"
EndProject
+Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Microsoft.CodeAnalysis.Razor.CohostingShared", "src\Razor\src\Microsoft.CodeAnalysis.Razor.CohostingShared\Microsoft.CodeAnalysis.Razor.CohostingShared.shproj", "{6778F3D4-C6C2-4882-9F86-54FCD44B078A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -587,15 +589,19 @@ Global
{094A024C-7DC1-487B-9F52-9D65CDFEE18D} = {92463391-81BE-462B-AC3C-78C6C760741F}
{440580F4-D746-49BB-AE8E-9F898483EA75} = {5B60F564-4AD7-4B70-A887-7D91496799A2}
{E102632D-EC30-474F-B2EB-6EB07ED45F27} = {440580F4-D746-49BB-AE8E-9F898483EA75}
+ {6778F3D4-C6C2-4882-9F86-54FCD44B078A} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0035341D-175A-4D05-95E6-F1C2785A1E26}
EndGlobalSection
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\Microsoft.AspNetCore.Razor.Serialization.Json\Microsoft.AspNetCore.Razor.Serialization.Json.projitems*{078aef36-f319-4ce2-baa2-5b58a6536b46}*SharedItemsImports = 5
+ src\Razor\src\Microsoft.CodeAnalysis.Razor.CohostingShared\Microsoft.CodeAnalysis.Razor.CohostingShared.projitems*{2223b8fd-d98a-47be-94a9-6a3a6b8557b8}*SharedItemsImports = 5
src\Shared\Microsoft.AspNetCore.Razor.Serialization.Json\Microsoft.AspNetCore.Razor.Serialization.Json.projitems*{6205467f-e381-4c42-aeec-763bd62b3d5e}*SharedItemsImports = 5
+ src\Razor\src\Microsoft.CodeAnalysis.Razor.CohostingShared\Microsoft.CodeAnalysis.Razor.CohostingShared.projitems*{6778f3d4-c6c2-4882-9f86-54fcd44b078a}*SharedItemsImports = 13
src\Shared\Microsoft.AspNetCore.Razor.Serialization.Json\Microsoft.AspNetCore.Razor.Serialization.Json.projitems*{7b1c5668-b4bc-45d9-ae4c-9c2382fc47a9}*SharedItemsImports = 5
src\Shared\Microsoft.AspNetCore.Razor.Serialization.Json\Microsoft.AspNetCore.Razor.Serialization.Json.projitems*{cd6913f3-ec47-4470-9c45-f5f898615e9d}*SharedItemsImports = 13
+ src\Razor\src\Microsoft.CodeAnalysis.Razor.CohostingShared\Microsoft.CodeAnalysis.Razor.CohostingShared.projitems*{e5d92db7-5cbf-410a-9685-ff76f71ec96f}*SharedItemsImports = 5
src\Shared\Microsoft.AspNetCore.Razor.Serialization.Json\Microsoft.AspNetCore.Razor.Serialization.Json.projitems*{e5d92db7-5cbf-410a-9685-ff76f71ec96f}*SharedItemsImports = 5
EndGlobalSection
EndGlobal
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index f5de9cfdb7b..5cfd70d6852 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -7,103 +7,99 @@
7dbf5deea5bdccf513df73cba179c4c0ad106010
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 09312a65870e883999ffe2ca25edd05cbc241e05
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
-
-
- https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
-
+
https://github.com/dotnet/roslyn
- 605d9346cdae106907f67663250788eff6048b09
+ 05e49aa98995349ffa26a19020333293ffe99670
diff --git a/eng/Versions.props b/eng/Versions.props
index 6d44c4e1c34..854fbc5afa8 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -47,32 +47,31 @@
-->
- 3.12.0-beta1.25209.6
+ 3.12.0-beta1.25222.12
9.0.0-alpha.1.25209.1
9.0.0-beta.25208.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25207.1
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
- 5.0.0-1.25209.6
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
+ 5.0.0-1.25222.12
$(NetVSCode)
- enable
enable
true
+ $(DefineConstants);VSCODE
+
@@ -65,4 +66,6 @@
+
+
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/RazorWorkspaceListener.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/RazorWorkspaceListener.cs
index 78fe8e5e316..e0f222d77b8 100644
--- a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/RazorWorkspaceListener.cs
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/RazorWorkspaceListener.cs
@@ -1,7 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
+using System.IO;
using System.IO.Pipes;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Logging;
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/RazorWorkspaceListenerBase.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/RazorWorkspaceListenerBase.cs
index a3ef36c0349..ba33053a9ea 100644
--- a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/RazorWorkspaceListenerBase.cs
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/RazorWorkspaceListenerBase.cs
@@ -1,8 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
+using System;
+using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.Utilities;
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/SemanticTokens/CohostSemanticTokensRegistration.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/SemanticTokens/CohostSemanticTokensRegistration.cs
new file mode 100644
index 00000000000..9ec610c45a9
--- /dev/null
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/SemanticTokens/CohostSemanticTokensRegistration.cs
@@ -0,0 +1,38 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System.Collections.Immutable;
+using System.Composition;
+using System.Text.Json;
+using Microsoft.AspNetCore.Razor.LanguageServer.Hosting;
+using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost;
+using Microsoft.CodeAnalysis.Razor.SemanticTokens;
+
+namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
+
+[Shared]
+[Export(typeof(IDynamicRegistrationProvider))]
+[method: ImportingConstructor]
+internal sealed class CohostSemanticTokensRegistration(ISemanticTokensLegendService semanticTokensLegendService) : IDynamicRegistrationProvider
+{
+ private readonly ISemanticTokensLegendService _semanticTokensLegendService = semanticTokensLegendService;
+
+ public ImmutableArray GetRegistrations(VSInternalClientCapabilities clientCapabilities, RazorCohostRequestContext requestContext)
+ {
+ if (clientCapabilities.TextDocument?.SemanticTokens?.DynamicRegistration == true)
+ {
+ var semanticTokensRefreshQueue = requestContext.GetRequiredService();
+ var clientCapabilitiesString = JsonSerializer.Serialize(clientCapabilities);
+ semanticTokensRefreshQueue.Initialize(clientCapabilitiesString);
+
+ return [new Registration()
+ {
+ Method = Methods.TextDocumentSemanticTokensName,
+ RegisterOptions = new SemanticTokensRegistrationOptions()
+ .EnableSemanticTokens(_semanticTokensLegendService)
+ }];
+ }
+
+ return [];
+ }
+}
\ No newline at end of file
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/ClientSettingsReader.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/ClientSettingsReader.cs
new file mode 100644
index 00000000000..2edeaeb9ab5
--- /dev/null
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/ClientSettingsReader.cs
@@ -0,0 +1,19 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System.Composition;
+using Microsoft.CodeAnalysis.Razor.Settings;
+using Microsoft.CodeAnalysis.Razor.Workspaces.Settings;
+
+namespace Microsoft.VisualStudioCode.RazorExtension.Services;
+
+[Shared]
+[Export(typeof(IClientSettingsReader))]
+internal class ClientSettingsReader : IClientSettingsReader
+{
+ public ClientSettings GetClientSettings()
+ {
+ // TODO: Implement logic to read client settings
+ return ClientSettings.Default;
+ }
+}
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/DynamicFileInfoProvider.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/DynamicFileInfoProvider.cs
index 769af8e35b7..ab84bd2987a 100644
--- a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/DynamicFileInfoProvider.cs
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/DynamicFileInfoProvider.cs
@@ -1,21 +1,31 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
+using System;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Features;
+using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.VisualStudioCode.RazorExtension.Services;
-internal sealed partial class LspDynamicFileProvider(IRazorClientLanguageServerManager clientLanguageServerManager) : RazorLspDynamicFileInfoProvider
+internal sealed partial class LspDynamicFileProvider(IRazorClientLanguageServerManager clientLanguageServerManager, LanguageServerFeatureOptions languageServerFeatureOptions) : RazorLspDynamicFileInfoProvider
{
private const string ProvideRazorDynamicFileInfoMethodName = "razor/provideDynamicFileInfo";
private const string RemoveRazorDynamicFileInfoMethodName = "razor/removeDynamicFileInfo";
private readonly IRazorClientLanguageServerManager _clientLanguageServerManager = clientLanguageServerManager;
+ private readonly LanguageServerFeatureOptions _languageServerFeatureOptions = languageServerFeatureOptions;
public override async Task GetDynamicFileInfoAsync(Workspace workspace, ProjectId projectId, string? projectFilePath, string filePath, CancellationToken cancellationToken)
{
+ if (_languageServerFeatureOptions.UseRazorCohostServer)
+ {
+ return null;
+ }
+
var razorUri = new Uri(filePath);
var requestParams = new RazorProvideDynamicFileParams
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/DynamicFileProviderFactory.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/DynamicFileProviderFactory.cs
index 05a47cca6f4..da91e709854 100644
--- a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/DynamicFileProviderFactory.cs
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/DynamicFileProviderFactory.cs
@@ -4,16 +4,20 @@
using System.Composition;
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Features;
+using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.VisualStudioCode.RazorExtension.Services;
[ExportRazorLspServiceFactory(typeof(RazorLspDynamicFileInfoProvider)), Shared]
-internal sealed class DynamicFileProviderFactory : AbstractRazorLspServiceFactory
+[method: ImportingConstructor]
+internal sealed class DynamicFileProviderFactory(LanguageServerFeatureOptions featureOptions) : AbstractRazorLspServiceFactory
{
+ private readonly LanguageServerFeatureOptions _featureOptions = featureOptions;
+
protected override AbstractRazorLspService CreateService(IRazorLspServices lspServices)
{
var clientLanguageServerManager = lspServices.GetRequiredService();
- return new LspDynamicFileProvider(clientLanguageServerManager);
+ return new LspDynamicFileProvider(clientLanguageServerManager, _featureOptions);
}
}
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/InProcServiceFactory.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/InProcServiceFactory.cs
new file mode 100644
index 00000000000..793c4bbe86d
--- /dev/null
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/InProcServiceFactory.cs
@@ -0,0 +1,66 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Razor;
+using Microsoft.CodeAnalysis.Razor.Logging;
+using Microsoft.CodeAnalysis.Remote.Razor;
+
+namespace Microsoft.VisualStudioCode.RazorExtension.Services;
+
+///
+/// Creates Razor brokered services.
+///
+///
+/// This class holds instances in a static
+/// field. This should work fine in tests, since brokered service factories are intended to be stateless.
+/// However, if a factory is introduced that maintains state, this class will need to be revisited to
+/// avoid holding onto state across tests.
+///
+internal static class InProcServiceFactory
+{
+ private static readonly Dictionary s_factoryMap = BuildFactoryMap();
+
+ private static Dictionary BuildFactoryMap()
+ {
+ var result = new Dictionary();
+
+ foreach (var type in typeof(RazorBrokeredServiceBase.FactoryBase<>).Assembly.GetTypes())
+ {
+ if (!type.IsAbstract &&
+ typeof(IInProcServiceFactory).IsAssignableFrom(type))
+ {
+ Assumes.True(typeof(RazorBrokeredServiceBase.FactoryBase<>) == type.BaseType!.GetGenericTypeDefinition());
+
+ var genericType = type.BaseType.GetGenericArguments().Single();
+
+ // ServiceHub requires a parameterless constructor, so we can safely rely on it existing too
+ var factory = (IInProcServiceFactory)Activator.CreateInstance(type).AssumeNotNull();
+ result.Add(genericType, factory);
+ }
+ }
+
+ return result;
+ }
+
+ public static async Task CreateServiceAsync(
+ VSCodeBrokeredServiceInterceptor brokeredServiceInterceptor, ILoggerFactory loggerFactory)
+ where TService : class
+ {
+ Assumes.True(s_factoryMap.TryGetValue(typeof(TService), out var factory));
+
+ var brokeredServiceData = new RazorBrokeredServiceData(ExportProvider: null, loggerFactory, brokeredServiceInterceptor);
+ var hostProvidedServices = new HostProvidedServices(brokeredServiceData);
+
+ return (TService)await factory.CreateInProcAsync(hostProvidedServices).ConfigureAwait(false);
+ }
+
+ private class HostProvidedServices(RazorBrokeredServiceData brokeredServiceData) : IServiceProvider
+ {
+ public object? GetService(Type serviceType)
+ => serviceType == typeof(RazorBrokeredServiceData) ? brokeredServiceData : null;
+ }
+}
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/LoggerFactory.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/LoggerFactory.cs
new file mode 100644
index 00000000000..dede048009f
--- /dev/null
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/LoggerFactory.cs
@@ -0,0 +1,15 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System.Composition;
+using Microsoft.CodeAnalysis.Razor.Logging;
+
+namespace Microsoft.AspNetCore.Razor.LanguageServer;
+
+[Shared]
+[Export(typeof(ILoggerFactory))]
+[method: ImportingConstructor]
+internal sealed class LoggerFactory(ILoggerProvider provider)
+ : AbstractLoggerFactory([provider])
+{
+}
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/LoggerProvider.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/LoggerProvider.cs
new file mode 100644
index 00000000000..b8ad83a9a4d
--- /dev/null
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/LoggerProvider.cs
@@ -0,0 +1,20 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System.Composition;
+using Microsoft.CodeAnalysis.Razor.Logging;
+
+namespace Microsoft.AspNetCore.Razor.LanguageServer;
+
+[Shared]
+[Export(typeof(ILoggerProvider))]
+[method: ImportingConstructor]
+internal class LoggerProvider(RazorClientServerManagerProvider razorClientServerManagerProvider) : ILoggerProvider
+{
+ private readonly RazorClientServerManagerProvider _razorClientServerManagerProvider = razorClientServerManagerProvider;
+
+ public ILogger CreateLogger(string categoryName)
+ {
+ return new LspLogger(categoryName, _razorClientServerManagerProvider);
+ }
+}
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/LspDynamicFileProvider.LspTextChangesTextLoader.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/LspDynamicFileProvider.LspTextChangesTextLoader.cs
index 718def982a7..9142f62f9dc 100644
--- a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/LspDynamicFileProvider.LspTextChangesTextLoader.cs
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/LspDynamicFileProvider.LspTextChangesTextLoader.cs
@@ -1,8 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
+using System;
+using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Linq;
using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
using Microsoft.CodeAnalysis.Razor.Protocol;
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/LspLogger.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/LspLogger.cs
new file mode 100644
index 00000000000..1e246da17f9
--- /dev/null
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/LspLogger.cs
@@ -0,0 +1,57 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System;
+using System.Threading;
+using Microsoft.CodeAnalysis.Razor.Logging;
+using Microsoft.VisualStudio.Threading;
+
+namespace Microsoft.AspNetCore.Razor.LanguageServer;
+
+///
+/// ILogger implementation that logs via the razor/log LSP method
+///
+///
+/// The handler for this custom log message is implemented in the C# extension and is responsible for writing the message to the output window.
+///
+internal class LspLogger(string categoryName, RazorClientServerManagerProvider razorClientServerManagerProvider) : ILogger
+{
+ private readonly string _categoryName = categoryName;
+ private readonly RazorClientServerManagerProvider _razorClientServerManagerProvider = razorClientServerManagerProvider;
+
+ public bool IsEnabled(LogLevel logLevel) => true;
+
+ public void Log(LogLevel logLevel, string message, Exception? exception)
+ {
+ if (_razorClientServerManagerProvider.ClientLanguageServerManager is not { } clientLanguageServerManager)
+ {
+ return;
+ }
+
+ if (!IsEnabled(logLevel))
+ {
+ return;
+ }
+
+ var messageType = logLevel switch
+ {
+ LogLevel.Critical => MessageType.Error,
+ LogLevel.Error => MessageType.Error,
+ LogLevel.Warning => MessageType.Warning,
+ LogLevel.Information => MessageType.Info,
+ LogLevel.Debug => MessageType.Log,
+ LogLevel.Trace => MessageType.Log,
+ _ => throw new NotImplementedException(),
+ };
+
+ var formattedMessage = LogMessageFormatter.FormatMessage(message, _categoryName, exception, includeTimeStamp: false);
+
+ var @params = new LogMessageParams
+ {
+ MessageType = messageType,
+ Message = formattedMessage,
+ };
+
+ clientLanguageServerManager.SendNotificationAsync("razor/log", @params, CancellationToken.None).Forget();
+ }
+}
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/RazorClientServerManagerProvider.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/RazorClientServerManagerProvider.cs
new file mode 100644
index 00000000000..0e140911796
--- /dev/null
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/RazorClientServerManagerProvider.cs
@@ -0,0 +1,28 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System.Composition;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.ExternalAccess.Razor;
+using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost;
+using Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
+
+namespace Microsoft.AspNetCore.Razor.LanguageServer;
+
+[Shared]
+[Export(typeof(IRazorCohostStartupService))]
+[Export(typeof(RazorClientServerManagerProvider))]
+[method: ImportingConstructor]
+internal class RazorClientServerManagerProvider() : IRazorCohostStartupService
+{
+ private IRazorClientLanguageServerManager? _razorClientLanguageServerManager;
+
+ public IRazorClientLanguageServerManager? ClientLanguageServerManager => _razorClientLanguageServerManager;
+
+ public Task StartupAsync(VSInternalClientCapabilities clientCapabilities, RazorCohostRequestContext requestContext, CancellationToken cancellationToken)
+ {
+ _razorClientLanguageServerManager = requestContext.GetRequiredService();
+ return Task.CompletedTask;
+ }
+}
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeBrokeredServiceInterceptor.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeBrokeredServiceInterceptor.cs
new file mode 100644
index 00000000000..2c317fe9031
--- /dev/null
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeBrokeredServiceInterceptor.cs
@@ -0,0 +1,21 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Razor;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.ExternalAccess.Razor;
+using Microsoft.CodeAnalysis.Remote.Razor;
+
+namespace Microsoft.VisualStudioCode.RazorExtension.Services;
+
+internal class VSCodeBrokeredServiceInterceptor : IRazorBrokeredServiceInterceptor
+{
+ public ValueTask RunServiceAsync(Func implementation, CancellationToken cancellationToken)
+ => implementation(cancellationToken);
+
+ public ValueTask RunServiceAsync(RazorPinnedSolutionInfoWrapper solutionInfo, Func> implementation, CancellationToken cancellationToken)
+ => implementation(solutionInfo.Solution.AssumeNotNull());
+}
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeLanguageServerFeatureOptions.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeLanguageServerFeatureOptions.cs
new file mode 100644
index 00000000000..e2411846e49
--- /dev/null
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeLanguageServerFeatureOptions.cs
@@ -0,0 +1,83 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System.Composition;
+using System.Text.Json.Nodes;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Razor.Utilities;
+using Microsoft.CodeAnalysis.ExternalAccess.Razor;
+using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost;
+using Microsoft.CodeAnalysis.Razor.Workspaces;
+using Microsoft.NET.Sdk.Razor.SourceGenerators;
+using Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
+
+namespace Microsoft.VisualStudioCode.RazorExtension.Services;
+
+[Shared]
+[Export(typeof(LanguageServerFeatureOptions))]
+internal class VSCodeLanguageServerFeatureOptions : LanguageServerFeatureOptions, IRazorCohostStartupService
+{
+ private bool _useRazorCohostServer = false;
+ private bool _useNewFormattingEngine = true;
+ private bool _forceRuntimeCodeGeneration = false;
+
+ // Options that are set to their defaults
+ public override bool SupportsFileManipulation => true;
+ public override bool SingleServerSupport => false;
+ public override bool UsePreciseSemanticTokenRanges => false;
+ public override bool ShowAllCSharpCodeActions => false;
+ public override bool ReturnCodeActionAndRenamePathsWithPrefixedSlash => PlatformInformation.IsWindows;
+ public override bool IncludeProjectKeyInGeneratedFilePath => false;
+ public override bool DoNotInitializeMiscFilesProjectFromWorkspace => false;
+
+ // Options that differ from the default
+ public override string CSharpVirtualDocumentSuffix => "__virtual.cs";
+ public override string HtmlVirtualDocumentSuffix => "__virtual.html";
+ public override bool UpdateBuffersForClosedDocuments => true;
+ public override bool DelegateToCSharpOnDiagnosticPublish => true;
+ public override bool SupportsSoftSelectionInCompletion => false;
+ public override bool UseVsCodeCompletionTriggerCharacters => true;
+
+ // User configurable options
+ public override bool UseRazorCohostServer => _useRazorCohostServer;
+ public override bool ForceRuntimeCodeGeneration => _forceRuntimeCodeGeneration;
+ public override bool UseNewFormattingEngine => _useNewFormattingEngine;
+
+ public async Task StartupAsync(VSInternalClientCapabilities clientCapabilities, RazorCohostRequestContext requestContext, CancellationToken cancellationToken)
+ {
+ var razorClientLanguageServerManager = requestContext.GetRequiredService();
+
+ // Attempt to get configurations from the client. If this throws we'll get NFW reports.
+ var configurationParams = new ConfigurationParams()
+ {
+ Items = [
+ // Roslyn's typescript config handler will convert underscores to camelcase, ie 'razor.languageServer.cohostingEnabled'
+ new ConfigurationItem { Section = "razor.language_server.cohosting_enabled" },
+ new ConfigurationItem { Section = "razor.language_server.use_new_formatting_engine" },
+ new ConfigurationItem { Section = "razor.language_server.force_runtime_code_generation" },
+
+ ]
+ };
+ var options = await razorClientLanguageServerManager.SendRequestAsync(
+ Methods.WorkspaceConfigurationName,
+ configurationParams,
+ cancellationToken).ConfigureAwait(false);
+
+ _useRazorCohostServer = GetBooleanOptionValue(options[0], _useRazorCohostServer);
+ _useNewFormattingEngine = GetBooleanOptionValue(options[1], _useNewFormattingEngine);
+ _forceRuntimeCodeGeneration = GetBooleanOptionValue(options[2], _forceRuntimeCodeGeneration);
+
+ RazorCohostingOptions.UseRazorCohostServer = _useRazorCohostServer;
+ }
+
+ private static bool GetBooleanOptionValue(JsonNode? jsonNode, bool defaultValue)
+ {
+ if (jsonNode is null)
+ {
+ return defaultValue;
+ }
+
+ return jsonNode.ToString() == "true";
+ }
+}
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeRemoteServiceInvoker.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeRemoteServiceInvoker.cs
new file mode 100644
index 00000000000..676cd4b952f
--- /dev/null
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeRemoteServiceInvoker.cs
@@ -0,0 +1,95 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Composition;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.ExternalAccess.Razor;
+using Microsoft.CodeAnalysis.Razor.Logging;
+using Microsoft.CodeAnalysis.Razor.Remote;
+using Microsoft.VisualStudio.Composition;
+
+namespace Microsoft.VisualStudioCode.RazorExtension.Services;
+
+[Shared]
+[Export(typeof(IRemoteServiceInvoker))]
+[method: ImportingConstructor]
+internal class VSCodeRemoteServiceInvoker(
+ ILoggerFactory loggerFactory) : IRemoteServiceInvoker, IDisposable
+{
+ private readonly ILoggerFactory _loggerFactory = loggerFactory;
+ private readonly Dictionary _services = [];
+ private readonly Lock _serviceLock = new();
+ private readonly VSCodeBrokeredServiceInterceptor _serviceInterceptor = new();
+
+ public async ValueTask TryInvokeAsync(
+ Solution solution,
+ Func> invocation,
+ CancellationToken cancellationToken,
+ [CallerFilePath] string? callerFilePath = null,
+ [CallerMemberName] string? callerMemberName = null) where TService : class
+ {
+ var service = await GetOrCreateServiceAsync().ConfigureAwait(false);
+
+ if (service == null)
+ {
+ // Service not available
+ return default;
+ }
+
+ // Get solution info with direct reference stored
+ var solutionInfo = new RazorPinnedSolutionInfoWrapper(checksum: default, solution: solution);
+
+ // Invoke the function with the service and solution info
+ return await invocation(service, solutionInfo, cancellationToken).ConfigureAwait(false);
+ }
+
+ private async Task GetOrCreateServiceAsync() where TService : class
+ {
+ lock (_serviceLock)
+ {
+ if (_services.TryGetValue(typeof(TService), out var existingService))
+ {
+ return (TService)existingService;
+ }
+ }
+
+ // Create the service using the InProcServiceFactory
+ try
+ {
+ var service = await InProcServiceFactory.CreateServiceAsync(_serviceInterceptor, _loggerFactory).ConfigureAwait(false);
+
+ lock (_serviceLock)
+ {
+ _services[typeof(TService)] = service;
+ }
+
+ return service;
+ }
+ catch (Exception)
+ {
+ // If service creation fails, return null
+ return null;
+ }
+ }
+
+ public void Dispose()
+ {
+ lock (_serviceLock)
+ {
+ foreach (var service in _services.Values)
+ {
+ if (service is IDisposable d)
+ {
+ d.Dispose();
+ }
+ }
+
+ _services.Clear();
+ }
+ }
+}
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeRemoteServicesInitializer.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeRemoteServicesInitializer.cs
new file mode 100644
index 00000000000..13d901f8c61
--- /dev/null
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeRemoteServicesInitializer.cs
@@ -0,0 +1,54 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System.Composition;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost;
+using Microsoft.CodeAnalysis.Razor.Logging;
+using Microsoft.CodeAnalysis.Razor.Remote;
+using Microsoft.CodeAnalysis.Razor.SemanticTokens;
+using Microsoft.CodeAnalysis.Razor.Workspaces;
+using Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
+
+namespace Microsoft.VisualStudioCode.RazorExtension.Services;
+
+[Shared]
+[Export(typeof(IRazorCohostStartupService))]
+[method: ImportingConstructor]
+internal class VSCodeRemoteServicesInitializer(
+ LanguageServerFeatureOptions featureOptions,
+ ISemanticTokensLegendService semanticTokensLegendService,
+ ILoggerFactory loggerFactory) : IRazorCohostStartupService
+{
+ private readonly LanguageServerFeatureOptions _featureOptions = featureOptions;
+ private readonly ISemanticTokensLegendService _semanticTokensLegendService = semanticTokensLegendService;
+ private readonly ILoggerFactory _loggerFactory = loggerFactory;
+
+ public async Task StartupAsync(VSInternalClientCapabilities clientCapabilities, RazorCohostRequestContext requestContext, CancellationToken cancellationToken)
+ {
+ // Normal remote service invoker logic requires a solution, but we don't have one here. Fortunately we don't need one, and since
+ // we know this is VS Code specific, its all just smoke and mirrors anyway. We can avoid the smoke :)
+ var serviceInterceptor = new VSCodeBrokeredServiceInterceptor();
+ var service = await InProcServiceFactory.CreateServiceAsync(serviceInterceptor, _loggerFactory).ConfigureAwait(false);
+
+ await service.InitializeAsync(new RemoteClientInitializationOptions
+ {
+ UseRazorCohostServer = _featureOptions.UseRazorCohostServer,
+ UsePreciseSemanticTokenRanges = _featureOptions.UsePreciseSemanticTokenRanges,
+ HtmlVirtualDocumentSuffix = _featureOptions.HtmlVirtualDocumentSuffix,
+ ReturnCodeActionAndRenamePathsWithPrefixedSlash = _featureOptions.ReturnCodeActionAndRenamePathsWithPrefixedSlash,
+ SupportsFileManipulation = _featureOptions.SupportsFileManipulation,
+ ShowAllCSharpCodeActions = _featureOptions.ShowAllCSharpCodeActions,
+ SupportsSoftSelectionInCompletion = _featureOptions.SupportsSoftSelectionInCompletion,
+ UseVsCodeCompletionTriggerCharacters = _featureOptions.UseVsCodeCompletionTriggerCharacters,
+ }, cancellationToken).ConfigureAwait(false);
+
+ await service.InitializeLSPAsync(new RemoteClientLSPInitializationOptions
+ {
+ ClientCapabilities = clientCapabilities,
+ TokenTypes = _semanticTokensLegendService.TokenTypes.All,
+ TokenModifiers = _semanticTokensLegendService.TokenModifiers.All,
+ }, cancellationToken).ConfigureAwait(false);
+ }
+}
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeTelemetryReporter.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeTelemetryReporter.cs
new file mode 100644
index 00000000000..e5ae9ff8bfd
--- /dev/null
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeTelemetryReporter.cs
@@ -0,0 +1,61 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the MIT license. See License.txt in the project root for license information.
+
+using System;
+using System.Composition;
+using Microsoft.CodeAnalysis.Razor.Telemetry;
+
+namespace Microsoft.VisualStudioCode.RazorExtension.Services;
+
+// TODO:
+
+[Shared]
+[Export(typeof(ITelemetryReporter))]
+internal class VSCodeTelemetryReporter : ITelemetryReporter
+{
+ public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport)
+ => TelemetryScope.Null;
+
+ public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, Property property)
+ => TelemetryScope.Null;
+
+ public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, Property property1, Property property2)
+ => TelemetryScope.Null;
+
+ public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, Property property1, Property property2, Property property3)
+ => TelemetryScope.Null;
+
+ public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, params ReadOnlySpan properties)
+ => TelemetryScope.Null;
+
+ public void ReportEvent(string name, Severity severity)
+ {
+ }
+
+ public void ReportEvent(string name, Severity severity, Property property)
+ {
+ }
+
+ public void ReportEvent(string name, Severity severity, Property property1, Property property2)
+ {
+ }
+
+ public void ReportEvent(string name, Severity severity, Property property1, Property property2, Property property3)
+ {
+ }
+
+ public void ReportEvent(string name, Severity severity, params ReadOnlySpan properties)
+ {
+ }
+
+ public void ReportFault(Exception exception, string? message, params object?[] @params)
+ {
+ }
+
+ public TelemetryScope TrackLspRequest(string lspMethodName, string lspServerName, TimeSpan minTimeToReport, Guid correlationId)
+ => TelemetryScope.Null;
+
+ public void ReportRequestTiming(string name, string? language, TimeSpan queuedDuration, TimeSpan requestDuration, TelemetryResult result)
+ {
+ }
+}
diff --git a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/WorkspaceService.cs b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/WorkspaceService.cs
index 420d6a7aa41..2b1ebb8941d 100644
--- a/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/WorkspaceService.cs
+++ b/src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/WorkspaceService.cs
@@ -1,26 +1,37 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
+using System.Collections.Generic;
using System.Composition;
+using System.Threading;
using Microsoft.AspNetCore.Razor;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Features;
+using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.Extensions.Logging;
namespace Microsoft.VisualStudioCode.RazorExtension.Services;
[ExportRazorStatelessLspService(typeof(RazorWorkspaceService)), Shared]
[method: ImportingConstructor]
-internal sealed class WorkspaceService(ILoggerFactory loggerFactory) : RazorWorkspaceService
+internal sealed class WorkspaceService(ILoggerFactory loggerFactory, LanguageServerFeatureOptions languageServerFeatureOptions) : RazorWorkspaceService
{
private readonly ILoggerFactory _loggerFactory = loggerFactory;
private readonly ILogger _logger = loggerFactory.CreateLogger();
private readonly Lock _initializeLock = new();
+ private readonly LanguageServerFeatureOptions _languageServerFeatureOptions = languageServerFeatureOptions;
+
private RazorWorkspaceListener? _razorWorkspaceListener;
private HashSet? _projectIdWithDynamicFiles = [];
public override void Initialize(Workspace workspace, string pipeName)
{
+ if (_languageServerFeatureOptions.UseRazorCohostServer)
+ {
+ // Cohost server doesn't need to initialize the workspace listener.
+ return;
+ }
+
HashSet projectsToInitialize;
lock (_initializeLock)
{
@@ -48,6 +59,12 @@ public override void Initialize(Workspace workspace, string pipeName)
public override void NotifyDynamicFile(ProjectId projectId)
{
+ if (_languageServerFeatureOptions.UseRazorCohostServer)
+ {
+ // Cohost server doesn't need to initialize the workspace listener.
+ return;
+ }
+
if (_razorWorkspaceListener is null)
{
lock (_initializeLock)
diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTest.cs
index cd80fb0f698..e025cd3b34d 100644
--- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTest.cs
+++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTest.cs
@@ -100,7 +100,7 @@ public void RegistrationsProvideFilter()
foreach (var endpoint in providers)
{
- if (endpoint is CohostSemanticTokensRangeEndpoint)
+ if (endpoint is CohostSemanticTokensRegistration)
{
// We can't currently test this, as the GetRegistrations method calls requestContext.GetRequiredService
// and we can't create a request context ourselves
diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTestBase.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTestBase.cs
index 219135e1c21..3b2861efa10 100644
--- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTestBase.cs
+++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostEndpointTestBase.cs
@@ -116,6 +116,10 @@ protected override async Task InitializeAsync()
UpdateClientLSPInitializationOptions(c => c);
_filePathService = new RemoteFilePathService(FeatureOptions);
+
+ // Force initialization and creation of the remote workspace. It will be filled in later.
+ await RemoteWorkspaceAccessor.TestAccessor.InitializeRemoteExportProviderBuilderAsync(Path.GetTempPath(), DisposalToken);
+ _ = RemoteWorkspaceAccessor.GetWorkspace();
}
private protected void UpdateClientInitializationOptions(Func mutation)
diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSemanticTokensRangeEndpointTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSemanticTokensRangeEndpointTest.cs
index ba51cfa1cce..731580a3bd4 100644
--- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSemanticTokensRangeEndpointTest.cs
+++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/CohostSemanticTokensRangeEndpointTest.cs
@@ -134,7 +134,7 @@ private async Task VerifySemanticTokensAsync(
var clientSettingsManager = new ClientSettingsManager([], null, null);
clientSettingsManager.Update(ClientAdvancedSettings.Default with { ColorBackground = colorBackground });
- var endpoint = new CohostSemanticTokensRangeEndpoint(RemoteServiceInvoker, clientSettingsManager, legend, NoOpTelemetryReporter.Instance);
+ var endpoint = new CohostSemanticTokensRangeEndpoint(RemoteServiceInvoker, clientSettingsManager, NoOpTelemetryReporter.Instance);
var span = new LinePositionSpan(new(0, 0), new(sourceText.Lines.Count, 0));