diff --git a/src/EditorFeatures/TestUtilities/Remote/InProcRemostHostClient.cs b/src/EditorFeatures/TestUtilities/Remote/InProcRemostHostClient.cs index 26bdab817b7871b2df64f442143ae93109d5dbf2..c185f1bfa27885af18de4b556d63bf91b6ea3388 100644 --- a/src/EditorFeatures/TestUtilities/Remote/InProcRemostHostClient.cs +++ b/src/EditorFeatures/TestUtilities/Remote/InProcRemostHostClient.cs @@ -48,7 +48,7 @@ public static async Task CreateAsync(Workspace workspace, bool { _inprocServices = inprocServices; - _rpc = new JsonRpc(stream, stream, target: this); + _rpc = new JsonRpc(new JsonRpcMessageHandler(stream, stream), target: this); _rpc.JsonSerializer.Converters.Add(AggregateJsonConverter.Instance); // handle disconnected situation diff --git a/src/VisualStudio/Core/Next/Remote/JsonRpcClient.cs b/src/VisualStudio/Core/Next/Remote/JsonRpcClient.cs index ca65856a6553af9a5cc0da267a926532c0a425bc..42e1d7d427efd64173d9f4cff68ce4fd9b4293cf 100644 --- a/src/VisualStudio/Core/Next/Remote/JsonRpcClient.cs +++ b/src/VisualStudio/Core/Next/Remote/JsonRpcClient.cs @@ -28,7 +28,7 @@ internal class JsonRpcClient : IDisposable var target = useThisAsCallback ? this : callbackTarget; _cancellationToken = cancellationToken; - _rpc = new JsonRpc(stream, stream, target); + _rpc = new JsonRpc(new JsonRpcMessageHandler(stream, stream), target); _rpc.JsonSerializer.Converters.Add(AggregateJsonConverter.Instance); _rpc.Disconnected += OnDisconnected; diff --git a/src/VisualStudio/Core/Next/Remote/JsonRpcMessageHandler.cs b/src/VisualStudio/Core/Next/Remote/JsonRpcMessageHandler.cs new file mode 100644 index 0000000000000000000000000000000000000000..81eb5c574a3f672c9d58738ac6734202b416d1fd --- /dev/null +++ b/src/VisualStudio/Core/Next/Remote/JsonRpcMessageHandler.cs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.IO; +using StreamJsonRpc; + +namespace Microsoft.VisualStudio.LanguageServices.Remote +{ + // This is a workaround for a limitation in vs-threading. + // https://github.com/dotnet/roslyn/issues/19042 + internal class JsonRpcMessageHandler : HeaderDelimitedMessageHandler + { + public JsonRpcMessageHandler(Stream sendingStream, Stream receivingStream) + : base(sendingStream, receivingStream) + { + } + + protected override void Dispose(bool disposing) + { + // Do not call base.Dispose. We do not want the AsyncSemaphore instances to be disposed due to a race + // condition. + + if (disposing) + { + ReceivingStream?.Dispose(); + SendingStream?.Dispose(); + } + } + } +} diff --git a/src/VisualStudio/Core/Next/Remote/ServiceHubRemoteHostClient.cs b/src/VisualStudio/Core/Next/Remote/ServiceHubRemoteHostClient.cs index 84f2348e5c5f34012c97985a28b0087ca07f6026..a4b9e2a3d9624d7719c54968d3c1bf34d11af659 100644 --- a/src/VisualStudio/Core/Next/Remote/ServiceHubRemoteHostClient.cs +++ b/src/VisualStudio/Core/Next/Remote/ServiceHubRemoteHostClient.cs @@ -106,7 +106,7 @@ private static async Task RegisterWorkspaceHostAsync(Workspace workspace, Remote _hostGroup = hostGroup; _timeout = TimeSpan.FromMilliseconds(workspace.Options.GetOption(RemoteHostOptions.RequestServiceTimeoutInMS)); - _rpc = new JsonRpc(stream, stream, target: this); + _rpc = new JsonRpc(new JsonRpcMessageHandler(stream, stream), target: this); _rpc.JsonSerializer.Converters.Add(AggregateJsonConverter.Instance); // handle disconnected situation diff --git a/src/VisualStudio/Core/Next/ServicesVisualStudio.Next.csproj b/src/VisualStudio/Core/Next/ServicesVisualStudio.Next.csproj index cb72409950a67f4b247f7895d540cdc1425ea8f7..d9ae8c0a7b6ba82ca072e15f3670f5091373829e 100644 --- a/src/VisualStudio/Core/Next/ServicesVisualStudio.Next.csproj +++ b/src/VisualStudio/Core/Next/ServicesVisualStudio.Next.csproj @@ -105,6 +105,7 @@ + diff --git a/src/Workspaces/Remote/Razor/RazorServiceHub.csproj b/src/Workspaces/Remote/Razor/RazorServiceHub.csproj index 6e29caea382bdebda5e34bf3ba20541881beb5f4..4351aeb3493ec40f9c4e7579e5cb5cfcbad40f95 100644 --- a/src/Workspaces/Remote/Razor/RazorServiceHub.csproj +++ b/src/Workspaces/Remote/Razor/RazorServiceHub.csproj @@ -44,6 +44,9 @@ + + Shared\JsonRpcMessageHandler.cs + Shared\RoslynJsonConverter.cs diff --git a/src/Workspaces/Remote/ServiceHub/ServiceHub.csproj b/src/Workspaces/Remote/ServiceHub/ServiceHub.csproj index 26d66f271df3bf10536f1f7872d91eb6bc0b66f6..1ab54a50d292b296f0fb6d84bb3a80a8a4e901e6 100644 --- a/src/Workspaces/Remote/ServiceHub/ServiceHub.csproj +++ b/src/Workspaces/Remote/ServiceHub/ServiceHub.csproj @@ -60,6 +60,9 @@ Telemetry\VSTelemetryLogger.cs + + Shared\JsonRpcMessageHandler.cs + diff --git a/src/Workspaces/Remote/ServiceHub/Shared/ServiceHubServiceBase.cs b/src/Workspaces/Remote/ServiceHub/Shared/ServiceHubServiceBase.cs index 44f7c95c5f080a6b70f71c2868bbbddc2287fc37..36336263409c7aa04d5ca0cea7a99c04af34d364 100644 --- a/src/Workspaces/Remote/ServiceHub/Shared/ServiceHubServiceBase.cs +++ b/src/Workspaces/Remote/ServiceHub/Shared/ServiceHubServiceBase.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Options; +using Microsoft.VisualStudio.LanguageServices.Remote; using Roslyn.Utilities; using StreamJsonRpc; @@ -66,7 +67,7 @@ protected ServiceHubServiceBase(IServiceProvider serviceProvider, Stream stream) // due to this issue - https://github.com/dotnet/roslyn/issues/16900#issuecomment-277378950 // all sub type must explicitly start JsonRpc once everything is // setup - Rpc = new JsonRpc(stream, stream, this); + Rpc = new JsonRpc(new JsonRpcMessageHandler(stream, stream), this); Rpc.JsonSerializer.Converters.Add(AggregateJsonConverter.Instance); Rpc.Disconnected += OnRpcDisconnected; }