Skip to content

Commit 4b6c2ca

Browse files
committed
Initialize feature flags in OOP early
1 parent 1c424f9 commit 4b6c2ca

File tree

7 files changed

+34
-12
lines changed

7 files changed

+34
-12
lines changed

src/Razor/src/Microsoft.CodeAnalysis.Razor.CohostingShared/CohostStartupService.cs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,60 @@
55
using System.Collections.Generic;
66
using System.Collections.Immutable;
77
using System.ComponentModel.Composition;
8-
using System.Text.Json;
98
using System.Threading;
109
using System.Threading.Tasks;
1110
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost;
1211
using Microsoft.CodeAnalysis.Razor.Logging;
13-
using Microsoft.CodeAnalysis.Razor.Protocol;
12+
using Microsoft.CodeAnalysis.Razor.Remote;
1413

1514
namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
1615

17-
[Export(typeof(ICohostStartupService))]
16+
[Export(typeof(AbstractRazorCohostLifecycleService))]
1817
[method: ImportingConstructor]
1918
internal sealed class CohostStartupService(
2019
[ImportMany] IEnumerable<Lazy<IRazorCohostStartupService>> lazyStartupServices,
21-
ILoggerFactory loggerFactory) : ICohostStartupService
20+
IRemoteServiceInvoker remoteServiceInvoker,
21+
ILoggerFactory loggerFactory) : AbstractRazorCohostLifecycleService
2222
{
2323
private readonly ImmutableArray<Lazy<IRazorCohostStartupService>> _lazyStartupServices = [.. lazyStartupServices];
24-
private readonly ILogger _logger = loggerFactory.GetOrCreateLogger<CohostStartupService>();
24+
private readonly IRemoteServiceInvoker _remoteServiceInvoker = remoteServiceInvoker;
2525

26-
public async Task StartupAsync(string clientCapabilitiesString, RazorCohostRequestContext requestContext, CancellationToken cancellationToken)
26+
public override Task LspServerIntializedAsync(CancellationToken cancellationToken)
2727
{
28-
var clientCapabilities = JsonSerializer.Deserialize<VSInternalClientCapabilities>(clientCapabilitiesString, JsonHelpers.JsonSerializerOptions) ?? new();
28+
return _remoteServiceInvoker.InitializeAsync().AsTask();
29+
}
30+
31+
public override async Task RazorActivatedAsync(ClientCapabilities clientCapabilities, RazorCohostRequestContext requestContext, CancellationToken cancellationToken)
32+
{
33+
// Normally loggers are fields, but this service gets created early so it's better to avoid the work in case Razor
34+
// never gets activated.
35+
var logger = loggerFactory.GetOrCreateLogger<CohostStartupService>();
2936

37+
var capabilities = clientCapabilities.ToVSInternalClientCapabilities();
3038
var providers = _lazyStartupServices.SelectAndOrderByAsArray(p => p.Value, p => p.Order);
3139

3240
foreach (var provider in providers)
3341
{
3442
if (cancellationToken.IsCancellationRequested)
3543
{
36-
_logger.LogInformation($"Razor extension startup cancelled.");
44+
logger.LogInformation($"Razor extension startup cancelled.");
3745
return;
3846
}
3947

4048
try
4149
{
42-
await provider.StartupAsync(clientCapabilities, requestContext, cancellationToken).ConfigureAwait(false);
50+
await provider.StartupAsync(capabilities, requestContext, cancellationToken).ConfigureAwait(false);
4351
}
4452
catch (Exception ex) when (ex is not OperationCanceledException)
4553
{
46-
_logger.LogError(ex, $"Error initializing Razor startup service '{provider.GetType().Name}'");
54+
logger.LogError(ex, $"Error initializing Razor startup service '{provider.GetType().Name}'");
4755
}
4856
}
4957

50-
_logger.LogInformation($"Razor extension startup finished.");
58+
logger.LogInformation($"Razor extension startup finished.");
59+
}
60+
61+
public override void Dispose()
62+
{
5163
}
5264
}

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Remote/IRemoteServiceInvoker.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ namespace Microsoft.CodeAnalysis.Razor.Remote;
1111

1212
internal interface IRemoteServiceInvoker
1313
{
14+
ValueTask InitializeAsync();
15+
1416
ValueTask<TResult?> TryInvokeAsync<TService, TResult>(
1517
Solution solution,
1618
Func<TService, RazorPinnedSolutionInfoWrapper, CancellationToken, ValueTask<TResult>> invocation,

src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Remote/RemoteServiceInvoker.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ private async static Task<RazorRemoteHostClient> GetJsonClientAsync(IWorkspacePr
130130
?? throw new InvalidOperationException($"Couldn't retrieve {nameof(RazorRemoteHostClient)} for JSON serialization.");
131131
}
132132

133-
private ValueTask InitializeAsync()
133+
public ValueTask InitializeAsync()
134134
{
135135
var oopInitialized = _initializeOOPTask is { Status: TaskStatus.RanToCompletion };
136136
var lspInitialized = _initializeLspTask is { Status: TaskStatus.RanToCompletion };

src/Razor/src/Microsoft.VisualStudioCode.RazorExtension/Services/VSCodeRemoteServiceInvoker.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ internal class VSCodeRemoteServiceInvoker(
2929
private readonly Lock _serviceLock = new();
3030
private readonly VSCodeBrokeredServiceInterceptor _serviceInterceptor = new();
3131

32+
public ValueTask InitializeAsync() => ValueTask.CompletedTask; // Initialization in VS Code is handled in VSCodeRemoteServicesInitializer
33+
3234
public async ValueTask<TResult?> TryInvokeAsync<TService, TResult>(
3335
Solution solution,
3436
Func<TService, RazorPinnedSolutionInfoWrapper, CancellationToken, ValueTask<TResult>> invocation,

src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/HtmlDocumentSynchronizerTest.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,8 @@ private class RemoteServiceInvoker(TextDocument document, Func<Task>? generateTa
326326
public bool OOPReturnsNull { get; set; }
327327
public Func<Task>? GenerateTask { get; set; } = generateTask;
328328

329+
public ValueTask InitializeAsync() => throw new NotImplementedException();
330+
329331
public async ValueTask<TResult?> TryInvokeAsync<TService, TResult>(Solution solution, Func<TService, RazorPinnedSolutionInfoWrapper, CancellationToken, ValueTask<TResult>> invocation, CancellationToken cancellationToken, [CallerFilePath] string? callerFilePath = null, [CallerMemberName] string? callerMemberName = null) where TService : class
330332
{
331333
Assert.Equal(typeof(string), typeof(TResult));

src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/HtmlRequestInvokerTest.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ private async Task MakeHtmlRequestAsync<TRequest>(TextDocument document, Uri htm
111111

112112
private class RemoteServiceInvoker : IRemoteServiceInvoker
113113
{
114+
public ValueTask InitializeAsync() => throw new NotImplementedException();
115+
114116
public ValueTask<TResult?> TryInvokeAsync<TService, TResult>(Solution solution, Func<TService, RazorPinnedSolutionInfoWrapper, CancellationToken, ValueTask<TResult>> invocation, CancellationToken cancellationToken, [CallerFilePath] string? callerFilePath = null, [CallerMemberName] string? callerMemberName = null) where TService : class
115117
{
116118
return new((TResult?)(object)"");

src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Cohost/TestRemoteServiceInvoker.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ internal sealed class TestRemoteServiceInvoker(
2828
private readonly Dictionary<Type, object> _services = [];
2929
private readonly ReentrantSemaphore _reentrantSemaphore = ReentrantSemaphore.Create(initialCount: 1, joinableTaskContext);
3030

31+
public ValueTask InitializeAsync() => throw new NotImplementedException();
32+
3133
private async Task<TService> GetOrCreateServiceAsync<TService>()
3234
where TService : class
3335
{

0 commit comments

Comments
 (0)